Compare commits
92
Commits
c915c064e8
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95de7ad674 | ||
|
|
4495b81769 | ||
|
|
999b1a073e | ||
|
|
1433657697 | ||
|
|
59077f0f72 | ||
|
|
645150039a | ||
|
|
8a5557f4ae | ||
|
|
b20a1640b2 | ||
|
|
aca9f459ed | ||
|
|
ef469ab043 | ||
|
|
d2f4137894 | ||
|
|
94b2105cd6 | ||
|
|
1d618ea39d | ||
|
|
c6694f6a28 | ||
|
|
631fec7c4d | ||
|
|
68c741d54d | ||
|
|
f9487b63b0 | ||
|
|
1a3dc080e6 | ||
|
|
1a227504e2 | ||
|
|
69d8927c12 | ||
|
|
9b5fd077d2 | ||
|
|
889415b22a | ||
|
|
da94e21dbe | ||
|
|
501783e9ae | ||
|
|
f1f2f2aa25 | ||
|
|
f2d08a85a5 | ||
|
|
44189938d7 | ||
|
|
c6536260c3 | ||
|
|
d22ff2cbc4 | ||
|
|
48d8902e98 | ||
|
|
b4349511f4 | ||
|
|
b42b16add7 | ||
|
|
8fd18eef4d | ||
|
|
1e7afa11d7 | ||
|
|
1cfcd76588 | ||
|
|
179f76114b | ||
|
|
65e559596b | ||
|
|
98c11ee33b | ||
|
|
2f4fec9ab9 | ||
|
|
a38e29c59d | ||
|
|
c6a435ed36 | ||
|
|
2e22ebf0b5 | ||
|
|
cd6269d406 | ||
|
|
9a9a4fe8c0 | ||
|
|
f163dacce5 | ||
|
|
7e7ca3d929 | ||
|
|
c00f37b930 | ||
|
|
ace5edfda2 | ||
|
|
17813f3fcf | ||
|
|
cce6e417df | ||
|
|
8eb572d038 | ||
|
|
cee65bd68e | ||
|
|
74d7a48c4b | ||
|
|
315d8895a7 | ||
|
|
4e9cfdde97 | ||
|
|
645b6d772d | ||
|
|
ae24fb1dd0 | ||
|
|
fe64639842 | ||
|
|
db9beac740 | ||
|
|
471b6a6c40 | ||
|
|
fe2b130915 | ||
|
|
67fdd24a19 | ||
|
|
0d6b32dc3c | ||
|
|
ffceb300db | ||
|
|
b818e2764c | ||
|
|
4b7d90f939 | ||
|
|
6a7c1c1281 | ||
|
|
fdbfda189f | ||
|
|
e496d889ba | ||
|
|
9967878886 | ||
|
|
51badd75f0 | ||
|
|
f6e841e623 | ||
|
|
28bd9cf353 | ||
|
|
892829adeb | ||
|
|
82fd57af9e | ||
|
|
2f25bfb2db | ||
|
|
7f12e5aaf3 | ||
|
|
78e40ca353 | ||
|
|
1231b16cc3 | ||
|
|
6cd3638a85 | ||
|
|
4aead25970 | ||
|
|
36b34b0df0 | ||
|
|
bf0bd19289 | ||
|
|
8cd9e6dfa8 | ||
|
|
f0a114f4e5 | ||
|
|
ac99bf128b | ||
|
|
2c66de888f | ||
|
|
8f4db57ed8 | ||
|
|
b6f922895f | ||
|
|
7aa8eb1778 | ||
|
|
1128e440d2 | ||
|
|
ac052fe1c1 |
+32
-5
@@ -82,6 +82,37 @@ namespace BAN::Math
|
|||||||
return x + 1;
|
return x + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<unsigned_integral T>
|
||||||
|
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
||||||
|
inline constexpr int clz(T x)
|
||||||
|
{
|
||||||
|
if constexpr (is_same_v<T, unsigned int>)
|
||||||
|
return __builtin_clz(x);
|
||||||
|
if constexpr (is_same_v<T, unsigned long>)
|
||||||
|
return __builtin_clzl(x);
|
||||||
|
return __builtin_clzll(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned_integral T> requires(sizeof(T) <= sizeof(unsigned long long))
|
||||||
|
inline constexpr int ctz(T x)
|
||||||
|
{
|
||||||
|
if constexpr (sizeof(T) <= sizeof(unsigned int))
|
||||||
|
return __builtin_ctz(x);
|
||||||
|
if constexpr (sizeof(T) <= sizeof(unsigned long))
|
||||||
|
return __builtin_ctzl(x);
|
||||||
|
return __builtin_ctzll(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned_integral T> requires(sizeof(T) <= sizeof(unsigned long long))
|
||||||
|
inline constexpr int popcount(T x)
|
||||||
|
{
|
||||||
|
if constexpr (sizeof(T) <= sizeof(unsigned int))
|
||||||
|
return __builtin_popcount(x);
|
||||||
|
if constexpr (sizeof(T) <= sizeof(unsigned long))
|
||||||
|
return __builtin_popcountl(x);
|
||||||
|
return __builtin_popcountll(x);
|
||||||
|
}
|
||||||
|
|
||||||
template<integral T>
|
template<integral T>
|
||||||
__attribute__((always_inline))
|
__attribute__((always_inline))
|
||||||
inline constexpr bool will_multiplication_overflow(T a, T b)
|
inline constexpr bool will_multiplication_overflow(T a, T b)
|
||||||
@@ -102,11 +133,7 @@ namespace BAN::Math
|
|||||||
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
||||||
inline constexpr T ilog2(T x)
|
inline constexpr T ilog2(T x)
|
||||||
{
|
{
|
||||||
if constexpr(is_same_v<T, unsigned int>)
|
return sizeof(T) * 8 - clz(x) - 1;
|
||||||
return sizeof(T) * 8 - __builtin_clz(x) - 1;
|
|
||||||
if constexpr(is_same_v<T, unsigned long>)
|
|
||||||
return sizeof(T) * 8 - __builtin_clzl(x) - 1;
|
|
||||||
return sizeof(T) * 8 - __builtin_clzll(x) - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is ugly but my clangd does not like including
|
// This is ugly but my clangd does not like including
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ This is my hobby operating system written in C++. Currently supports x86\_64 and
|
|||||||
|
|
||||||
You can find a live demo [here](https://bananymous.com/banan-os)
|
You can find a live demo [here](https://bananymous.com/banan-os)
|
||||||
|
|
||||||
If you want to try out DOOM, you should first enter the GUI environment using the `start-gui` command. Then you can run `doom` in the GUI terminal.
|

|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
@@ -18,6 +18,8 @@ If you want to try out DOOM, you should first enter the GUI environment using th
|
|||||||
- [x] SMP (multiprocessing)
|
- [x] SMP (multiprocessing)
|
||||||
- [x] Linear framebuffer (VESA and GOP)
|
- [x] Linear framebuffer (VESA and GOP)
|
||||||
- [x] Network stack
|
- [x] Network stack
|
||||||
|
- [x] USB stack
|
||||||
|
- [x] Audio support
|
||||||
- [x] ELF executable loading
|
- [x] ELF executable loading
|
||||||
- [x] AML interpreter (partial)
|
- [x] AML interpreter (partial)
|
||||||
- [x] Basic graphical environment
|
- [x] Basic graphical environment
|
||||||
@@ -27,16 +29,14 @@ If you want to try out DOOM, you should first enter the GUI environment using th
|
|||||||
- [ ] Some nice apps
|
- [ ] Some nice apps
|
||||||
- [x] ELF dynamic linking
|
- [x] ELF dynamic linking
|
||||||
- [x] copy-on-write memory
|
- [x] copy-on-write memory
|
||||||
- [x] file mappings
|
|
||||||
- [ ] anonymous mappings
|
|
||||||
|
|
||||||
#### Drivers
|
#### Drivers
|
||||||
- [x] NVMe disks
|
- [x] NVMe disks
|
||||||
- [x] ATA (IDE, SATA) disks
|
- [x] ATA (IDE, SATA) disks
|
||||||
- [x] E1000 and E1000E NICs
|
- [x] E1000 and E1000E NICs
|
||||||
- [x] RTL8111/8168/8211/8411 NICs
|
- [x] RTL8111/8168/8211/8411 NICs
|
||||||
- [x] PS2 keyboard (all scancode sets)
|
- [x] AC97 and iHDA audio cards
|
||||||
- [x] PS2 mouse
|
- [x] PS2 keyboard and mouse
|
||||||
- [x] USB
|
- [x] USB
|
||||||
- [x] xHCI
|
- [x] xHCI
|
||||||
- [ ] EHCI
|
- [ ] EHCI
|
||||||
@@ -46,7 +46,8 @@ If you want to try out DOOM, you should first enter the GUI environment using th
|
|||||||
- [x] Mouse
|
- [x] Mouse
|
||||||
- [x] Mass storage
|
- [x] Mass storage
|
||||||
- [x] Hubs
|
- [x] Hubs
|
||||||
- [ ] ...
|
- [ ] Network
|
||||||
|
- [ ] Audio
|
||||||
- [ ] virtio devices (network, storage)
|
- [ ] virtio devices (network, storage)
|
||||||
|
|
||||||
#### Network
|
#### Network
|
||||||
@@ -54,7 +55,7 @@ If you want to try out DOOM, you should first enter the GUI environment using th
|
|||||||
- [x] ICMP
|
- [x] ICMP
|
||||||
- [x] IPv4
|
- [x] IPv4
|
||||||
- [x] UDP
|
- [x] UDP
|
||||||
- [x] TCP (partial and buggy)
|
- [x] TCP
|
||||||
- [x] Unix domain sockets
|
- [x] Unix domain sockets
|
||||||
- [ ] SSL
|
- [ ] SSL
|
||||||
|
|
||||||
@@ -65,7 +66,6 @@ If you want to try out DOOM, you should first enter the GUI environment using th
|
|||||||
- [x] Dev
|
- [x] Dev
|
||||||
- [x] Ram
|
- [x] Ram
|
||||||
- [x] Proc
|
- [x] Proc
|
||||||
- [ ] Sys
|
|
||||||
- [ ] 9P
|
- [ ] 9P
|
||||||
|
|
||||||
#### Bootloader support
|
#### Bootloader support
|
||||||
@@ -73,8 +73,6 @@ If you want to try out DOOM, you should first enter the GUI environment using th
|
|||||||
- [x] Custom BIOS bootloader
|
- [x] Custom BIOS bootloader
|
||||||
- [ ] Custom UEFI bootloader
|
- [ ] Custom UEFI bootloader
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Code structure
|
## Code structure
|
||||||
|
|
||||||
Each major component and library has its own subdirectory (kernel, userspace, libc, ...). Each directory contains directory *include*, which has **all** of the header files of the component. Every header is included by its absolute path.
|
Each major component and library has its own subdirectory (kernel, userspace, libc, ...). Each directory contains directory *include*, which has **all** of the header files of the component. Every header is included by its absolute path.
|
||||||
@@ -125,8 +123,22 @@ If you have corrupted your disk image or want to create new one, you can either
|
|||||||
./bos image-full
|
./bos image-full
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To test on real hardware, I have a script to generate a compressed ISO. The ISO can be copied directly to an USB drive with for example `dd`. The file is created at build/banan-os.iso and can be generated with
|
||||||
|
```sh
|
||||||
|
./bos iso
|
||||||
|
```
|
||||||
|
|
||||||
I have also created shell completion script for zsh. You can either copy the file in _script/shell-completion/zsh/\_bos_ to _/usr/share/zsh/site-functions/_ or add the _script/shell-completion/zsh_ to your fpath in _.zshrc_.
|
I have also created shell completion script for zsh. You can either copy the file in _script/shell-completion/zsh/\_bos_ to _/usr/share/zsh/site-functions/_ or add the _script/shell-completion/zsh_ to your fpath in _.zshrc_.
|
||||||
|
|
||||||
|
### Package Manager
|
||||||
|
|
||||||
|
banan-os uses xbps as its package manager for ports. All upstream ports are packaged into xbps packages hosted on a [repository on my server](https://packages.bananymous.com/banan-os). You can manage sysroot's xbps packages with `./bos` wrapper. You can use `xbps-install`, `xbps-remove` and `xbps-query` with repository and sysroot set to the correct values. For example to install xbps that can be used inside banan-os you can use
|
||||||
|
```sh
|
||||||
|
./bos xbps-install -S xbps
|
||||||
|
```
|
||||||
|
For xbps usage see [their documentation](https://docs.voidlinux.org/xbps/index.html).
|
||||||
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
As the upstream is hosted on my server https://git.bananymous.com/Bananymous/banan-os, merging contributions is not as trivial as it would be on GitHub. You can still send PRs in GitHub in which case I should be able to download the diff and apply it manually. If you want, I can also provide you an account to my git server. In this case please contact me ([email](mailto:[email protected]), [discord](https://discord.gg/ehjGySwYdK)).
|
As the upstream is hosted on my server https://git.bananymous.com/Bananymous/banan-os, merging contributions is not as trivial as it would be on GitHub. You can still send PRs in GitHub in which case I should be able to download the diff and apply it manually. If you want, I can also provide you an account to my git server. In this case please contact me ([email](mailto:[email protected]), [discord](https://discord.gg/ehjGySwYdK)).
|
||||||
|
|||||||
Binary file not shown.
@@ -41,6 +41,7 @@ set(KERNEL_SOURCES
|
|||||||
kernel/FS/USTARModule.cpp
|
kernel/FS/USTARModule.cpp
|
||||||
kernel/FS/VirtualFileSystem.cpp
|
kernel/FS/VirtualFileSystem.cpp
|
||||||
kernel/GDT.cpp
|
kernel/GDT.cpp
|
||||||
|
kernel/Graphics/BGA.cpp
|
||||||
kernel/IDT.cpp
|
kernel/IDT.cpp
|
||||||
kernel/Input/InputDevice.cpp
|
kernel/Input/InputDevice.cpp
|
||||||
kernel/Input/PS2/Controller.cpp
|
kernel/Input/PS2/Controller.cpp
|
||||||
@@ -51,6 +52,8 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Interruptable.cpp
|
kernel/Interruptable.cpp
|
||||||
kernel/InterruptController.cpp
|
kernel/InterruptController.cpp
|
||||||
kernel/kernel.cpp
|
kernel/kernel.cpp
|
||||||
|
kernel/Lock/Mutex.cpp
|
||||||
|
kernel/Lock/RWLock.cpp
|
||||||
kernel/Lock/SpinLock.cpp
|
kernel/Lock/SpinLock.cpp
|
||||||
kernel/Memory/ByteRingBuffer.cpp
|
kernel/Memory/ByteRingBuffer.cpp
|
||||||
kernel/Memory/DMARegion.cpp
|
kernel/Memory/DMARegion.cpp
|
||||||
@@ -83,6 +86,7 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Processor.cpp
|
kernel/Processor.cpp
|
||||||
kernel/Random.cpp
|
kernel/Random.cpp
|
||||||
kernel/Scheduler.cpp
|
kernel/Scheduler.cpp
|
||||||
|
kernel/SchedulerThreadNode.cpp
|
||||||
kernel/SSP.cpp
|
kernel/SSP.cpp
|
||||||
kernel/Storage/ATA/AHCI/Controller.cpp
|
kernel/Storage/ATA/AHCI/Controller.cpp
|
||||||
kernel/Storage/ATA/AHCI/Device.cpp
|
kernel/Storage/ATA/AHCI/Device.cpp
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ sys_fork_trampoline:
|
|||||||
|
|
||||||
call read_ip
|
call read_ip
|
||||||
testl %eax, %eax
|
testl %eax, %eax
|
||||||
jz .done
|
jz .Lsys_fork_trampoline_done
|
||||||
|
|
||||||
movl %esp, %ebx
|
movl %esp, %ebx
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ sys_fork_trampoline:
|
|||||||
call sys_fork
|
call sys_fork
|
||||||
addl $16, %esp
|
addl $16, %esp
|
||||||
|
|
||||||
.done:
|
.Lsys_fork_trampoline_done:
|
||||||
popl %edi
|
popl %edi
|
||||||
popl %esi
|
popl %esi
|
||||||
popl %ebx
|
popl %ebx
|
||||||
|
|||||||
@@ -28,27 +28,26 @@ safe_user_strncpy:
|
|||||||
testl %ecx, %ecx
|
testl %ecx, %ecx
|
||||||
jz safe_user_strncpy_fault
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
.safe_user_strncpy_loop:
|
.Lsafe_user_strncpy_loop:
|
||||||
movb (%esi), %al
|
movb (%esi), %al
|
||||||
movb %al, (%edi)
|
movb %al, (%edi)
|
||||||
testb %al, %al
|
testb %al, %al
|
||||||
jz .safe_user_strncpy_done
|
jz .Lsafe_user_strncpy_done
|
||||||
|
|
||||||
incl %edi
|
incl %edi
|
||||||
incl %esi
|
incl %esi
|
||||||
decl %ecx
|
decl %ecx
|
||||||
jnz .safe_user_strncpy_loop
|
jnz .Lsafe_user_strncpy_loop
|
||||||
|
|
||||||
safe_user_strncpy_fault:
|
safe_user_strncpy_fault:
|
||||||
xorl %eax, %eax
|
xorl %eax, %eax
|
||||||
jmp .safe_user_strncpy_return
|
jmp .Lsafe_user_strncpy_return
|
||||||
|
|
||||||
.safe_user_strncpy_done:
|
.Lsafe_user_strncpy_done:
|
||||||
movl $1, %eax
|
movl $1, %eax
|
||||||
|
|
||||||
.safe_user_strncpy_return:
|
.Lsafe_user_strncpy_return:
|
||||||
movl 4(%esp), %edi
|
movl 4(%esp), %edi
|
||||||
movl 8(%esp), %esi
|
movl 8(%esp), %esi
|
||||||
ret
|
ret
|
||||||
|
|
||||||
safe_user_strncpy_end:
|
safe_user_strncpy_end:
|
||||||
|
|||||||
+15
-17
@@ -168,14 +168,12 @@ has_sse:
|
|||||||
|
|
||||||
check_requirements:
|
check_requirements:
|
||||||
call has_cpuid
|
call has_cpuid
|
||||||
jz .exit
|
jz system_halt
|
||||||
call has_pae
|
call has_pae
|
||||||
jz .exit
|
jz system_halt
|
||||||
call has_sse
|
call has_sse
|
||||||
jz .exit
|
jz system_halt
|
||||||
ret
|
ret
|
||||||
.exit:
|
|
||||||
jmp system_halt
|
|
||||||
|
|
||||||
enable_sse:
|
enable_sse:
|
||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
@@ -225,8 +223,8 @@ _start:
|
|||||||
|
|
||||||
# load boot GDT
|
# load boot GDT
|
||||||
lgdt V2P(boot_gdtr)
|
lgdt V2P(boot_gdtr)
|
||||||
ljmpl $0x08, $V2P(gdt_flush)
|
ljmpl $0x08, $V2P(.Lgdt_flush)
|
||||||
gdt_flush:
|
.Lgdt_flush:
|
||||||
# set correct segment registers
|
# set correct segment registers
|
||||||
movw $0x10, %ax
|
movw $0x10, %ax
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
@@ -243,10 +241,10 @@ gdt_flush:
|
|||||||
movl $g_boot_stack_top, %esp
|
movl $g_boot_stack_top, %esp
|
||||||
|
|
||||||
# jump to higher half
|
# jump to higher half
|
||||||
leal higher_half, %ecx
|
leal .Lhigher_half, %ecx
|
||||||
jmp *%ecx
|
jmp *%ecx
|
||||||
|
|
||||||
higher_half:
|
.Lhigher_half:
|
||||||
# call global constuctors
|
# call global constuctors
|
||||||
call _init
|
call _init
|
||||||
|
|
||||||
@@ -298,18 +296,18 @@ ap_ready:
|
|||||||
.skip 4
|
.skip 4
|
||||||
|
|
||||||
1: cli; cld
|
1: cli; cld
|
||||||
ljmpl $0x00, $AP_REL(ap_cs_clear)
|
ljmpl $0x00, $AP_REL(.Lap_cs_clear)
|
||||||
|
|
||||||
ap_cs_clear:
|
.Lap_cs_clear:
|
||||||
# load ap gdt and enter protected mode
|
# load ap gdt and enter protected mode
|
||||||
lgdt AP_REL(ap_gdtr)
|
lgdt AP_REL(ap_gdtr)
|
||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
orb $1, %al
|
orb $1, %al
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
ljmpl $0x08, $AP_REL(ap_protected_mode)
|
ljmpl $0x08, $AP_REL(.Lap_protected_mode)
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
ap_protected_mode:
|
.Lap_protected_mode:
|
||||||
movw $0x10, %ax
|
movw $0x10, %ax
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
movw %ax, %ss
|
movw %ax, %ss
|
||||||
@@ -323,13 +321,13 @@ ap_protected_mode:
|
|||||||
|
|
||||||
# load boot gdt and enter long mode
|
# load boot gdt and enter long mode
|
||||||
lgdt V2P(boot_gdtr)
|
lgdt V2P(boot_gdtr)
|
||||||
ljmpl $0x08, $AP_REL(ap_flush_gdt)
|
ljmpl $0x08, $AP_REL(.Lap_flush_gdt)
|
||||||
|
|
||||||
ap_flush_gdt:
|
.Lap_flush_gdt:
|
||||||
movl $ap_higher_half, %ecx
|
movl $.Lap_higher_half, %ecx
|
||||||
jmp *%ecx
|
jmp *%ecx
|
||||||
|
|
||||||
ap_higher_half:
|
.Lap_higher_half:
|
||||||
movl AP_REL(ap_prepare_paging), %eax
|
movl AP_REL(ap_prepare_paging), %eax
|
||||||
call *%eax
|
call *%eax
|
||||||
|
|
||||||
|
|||||||
@@ -33,13 +33,13 @@ sys_fork_trampoline:
|
|||||||
|
|
||||||
call read_ip
|
call read_ip
|
||||||
testq %rax, %rax
|
testq %rax, %rax
|
||||||
jz .done
|
jz .Lsys_fork_trampoline_done
|
||||||
|
|
||||||
movq %rax, %rsi
|
movq %rax, %rsi
|
||||||
movq %rsp, %rdi
|
movq %rsp, %rdi
|
||||||
call sys_fork
|
call sys_fork
|
||||||
|
|
||||||
.done:
|
.Lsys_fork_trampoline_done:
|
||||||
popq %r15
|
popq %r15
|
||||||
popq %r14
|
popq %r14
|
||||||
popq %r13
|
popq %r13
|
||||||
|
|||||||
+14
-14
@@ -20,28 +20,28 @@ safe_user_strncpy:
|
|||||||
testq %rcx, %rcx
|
testq %rcx, %rcx
|
||||||
jz safe_user_strncpy_fault
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
.safe_user_strncpy_align_loop:
|
.Lsafe_user_strncpy_align_loop:
|
||||||
testb $0x7, %sil
|
testb $0x7, %sil
|
||||||
jz .safe_user_strncpy_align_done
|
jz .Lsafe_user_strncpy_align_done
|
||||||
|
|
||||||
movb (%rsi), %al
|
movb (%rsi), %al
|
||||||
movb %al, (%rdi)
|
movb %al, (%rdi)
|
||||||
testb %al, %al
|
testb %al, %al
|
||||||
jz .safe_user_strncpy_done
|
jz .Lsafe_user_strncpy_done
|
||||||
|
|
||||||
incq %rdi
|
incq %rdi
|
||||||
incq %rsi
|
incq %rsi
|
||||||
decq %rcx
|
decq %rcx
|
||||||
jnz .safe_user_strncpy_align_loop
|
jnz .Lsafe_user_strncpy_align_loop
|
||||||
jmp safe_user_strncpy_fault
|
jmp safe_user_strncpy_fault
|
||||||
|
|
||||||
.safe_user_strncpy_align_done:
|
.Lsafe_user_strncpy_align_done:
|
||||||
movq $0x0101010101010101, %r8
|
movq $0x0101010101010101, %r8
|
||||||
movq $0x8080808080808080, %r9
|
movq $0x8080808080808080, %r9
|
||||||
|
|
||||||
.safe_user_strncpy_qword_loop:
|
.Lsafe_user_strncpy_qword_loop:
|
||||||
cmpq $8, %rcx
|
cmpq $8, %rcx
|
||||||
jb .safe_user_strncpy_qword_done
|
jb .Lsafe_user_strncpy_qword_done
|
||||||
|
|
||||||
movq (%rsi), %rax
|
movq (%rsi), %rax
|
||||||
movq %rax, %r10
|
movq %rax, %r10
|
||||||
@@ -52,36 +52,36 @@ safe_user_strncpy:
|
|||||||
notq %r11
|
notq %r11
|
||||||
andq %r11, %r10
|
andq %r11, %r10
|
||||||
andq %r9, %r10
|
andq %r9, %r10
|
||||||
jnz .safe_user_strncpy_byte_loop
|
jnz .Lsafe_user_strncpy_byte_loop
|
||||||
|
|
||||||
movq %rax, (%rdi)
|
movq %rax, (%rdi)
|
||||||
|
|
||||||
addq $8, %rdi
|
addq $8, %rdi
|
||||||
addq $8, %rsi
|
addq $8, %rsi
|
||||||
subq $8, %rcx
|
subq $8, %rcx
|
||||||
jnz .safe_user_strncpy_qword_loop
|
jnz .Lsafe_user_strncpy_qword_loop
|
||||||
jmp safe_user_strncpy_fault
|
jmp safe_user_strncpy_fault
|
||||||
|
|
||||||
.safe_user_strncpy_qword_done:
|
.Lsafe_user_strncpy_qword_done:
|
||||||
testq %rcx, %rcx
|
testq %rcx, %rcx
|
||||||
jz safe_user_strncpy_fault
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
.safe_user_strncpy_byte_loop:
|
.Lsafe_user_strncpy_byte_loop:
|
||||||
movb (%rsi), %al
|
movb (%rsi), %al
|
||||||
movb %al, (%rdi)
|
movb %al, (%rdi)
|
||||||
testb %al, %al
|
testb %al, %al
|
||||||
jz .safe_user_strncpy_done
|
jz .Lsafe_user_strncpy_done
|
||||||
|
|
||||||
incq %rdi
|
incq %rdi
|
||||||
incq %rsi
|
incq %rsi
|
||||||
decq %rcx
|
decq %rcx
|
||||||
jnz .safe_user_strncpy_byte_loop
|
jnz .Lsafe_user_strncpy_byte_loop
|
||||||
|
|
||||||
safe_user_strncpy_fault:
|
safe_user_strncpy_fault:
|
||||||
xorq %rax, %rax
|
xorq %rax, %rax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.safe_user_strncpy_done:
|
.Lsafe_user_strncpy_done:
|
||||||
movb $1, %al
|
movb $1, %al
|
||||||
ret
|
ret
|
||||||
safe_user_strncpy_end:
|
safe_user_strncpy_end:
|
||||||
|
|||||||
+14
-16
@@ -161,12 +161,10 @@ is_64_bit:
|
|||||||
|
|
||||||
check_requirements:
|
check_requirements:
|
||||||
call has_cpuid
|
call has_cpuid
|
||||||
jz .exit
|
jz system_halt
|
||||||
call is_64_bit
|
call is_64_bit
|
||||||
jz .exit
|
jz system_halt
|
||||||
ret
|
ret
|
||||||
.exit:
|
|
||||||
jmp system_halt
|
|
||||||
|
|
||||||
enable_sse:
|
enable_sse:
|
||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
@@ -226,10 +224,10 @@ _start:
|
|||||||
|
|
||||||
# flush gdt and jump to 64 bit
|
# flush gdt and jump to 64 bit
|
||||||
lgdt V2P(boot_gdtr)
|
lgdt V2P(boot_gdtr)
|
||||||
ljmpl $0x08, $V2P(long_mode)
|
ljmpl $0x08, $V2P(.Llong_mode)
|
||||||
|
|
||||||
.code64
|
.code64
|
||||||
long_mode:
|
.Llong_mode:
|
||||||
movw $0x10, %ax
|
movw $0x10, %ax
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
movw %ax, %ss
|
movw %ax, %ss
|
||||||
@@ -240,10 +238,10 @@ long_mode:
|
|||||||
addq $KERNEL_OFFSET, %rsp
|
addq $KERNEL_OFFSET, %rsp
|
||||||
|
|
||||||
# jump to higher half
|
# jump to higher half
|
||||||
movabsq $higher_half, %rcx
|
movabsq $.Lhigher_half, %rcx
|
||||||
jmp *%rcx
|
jmp *%rcx
|
||||||
|
|
||||||
higher_half:
|
.Lhigher_half:
|
||||||
# call global constuctors
|
# call global constuctors
|
||||||
call _init
|
call _init
|
||||||
|
|
||||||
@@ -293,18 +291,18 @@ ap_ready:
|
|||||||
.skip 8
|
.skip 8
|
||||||
|
|
||||||
1: cli; cld
|
1: cli; cld
|
||||||
ljmpl $0x00, $AP_REL(ap_cs_clear)
|
ljmpl $0x00, $AP_REL(.Lap_cs_clear)
|
||||||
|
|
||||||
ap_cs_clear:
|
.Lap_cs_clear:
|
||||||
# load ap gdt and enter protected mode
|
# load ap gdt and enter protected mode
|
||||||
lgdt AP_REL(ap_gdtr)
|
lgdt AP_REL(ap_gdtr)
|
||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
orb $1, %al
|
orb $1, %al
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
ljmpl $0x08, $AP_REL(ap_protected_mode)
|
ljmpl $0x08, $AP_REL(.Lap_protected_mode)
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
ap_protected_mode:
|
.Lap_protected_mode:
|
||||||
movw $0x10, %ax
|
movw $0x10, %ax
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
movw %ax, %ss
|
movw %ax, %ss
|
||||||
@@ -318,14 +316,14 @@ ap_protected_mode:
|
|||||||
|
|
||||||
# load boot gdt and enter long mode
|
# load boot gdt and enter long mode
|
||||||
lgdt V2P(boot_gdtr)
|
lgdt V2P(boot_gdtr)
|
||||||
ljmpl $0x08, $AP_REL(ap_long_mode)
|
ljmpl $0x08, $AP_REL(.Lap_long_mode)
|
||||||
|
|
||||||
.code64
|
.code64
|
||||||
ap_long_mode:
|
.Lap_long_mode:
|
||||||
movq $ap_higher_half, %rax
|
movq $.Lap_higher_half, %rax
|
||||||
jmp *%rax
|
jmp *%rax
|
||||||
|
|
||||||
ap_higher_half:
|
.Lap_higher_half:
|
||||||
movq AP_REL(ap_prepare_paging), %rax
|
movq AP_REL(ap_prepare_paging), %rax
|
||||||
call *%rax
|
call *%rax
|
||||||
|
|
||||||
|
|||||||
+29
-15
@@ -38,25 +38,39 @@ extern "C" void __cxa_finalize(void* f)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace __cxxabiv1
|
extern "C" int __cxa_guard_acquire(uint64_t* g)
|
||||||
{
|
{
|
||||||
using __guard = uint64_t;
|
uint8_t* guard = reinterpret_cast<uint8_t*>(g);
|
||||||
|
|
||||||
extern "C" int __cxa_guard_acquire (__guard* g)
|
for (;;)
|
||||||
{
|
{
|
||||||
uint8_t* byte = reinterpret_cast<uint8_t*>(g);
|
if (BAN::atomic_load(guard[0], BAN::memory_order_acquire))
|
||||||
uint8_t zero = 0;
|
return 0;
|
||||||
return __atomic_compare_exchange_n(byte, &zero, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void __cxa_guard_release (__guard* g)
|
uint8_t expected = 0;
|
||||||
{
|
if (BAN::atomic_compare_exchange(guard[1], expected, 1, BAN::memory_order_acquire))
|
||||||
uint8_t* byte = reinterpret_cast<uint8_t*>(g);
|
{
|
||||||
__atomic_store_n(byte, 0, __ATOMIC_RELEASE);
|
if (BAN::atomic_load(guard[0], BAN::memory_order_acquire))
|
||||||
}
|
{
|
||||||
|
BAN::atomic_store(guard[1], 0, BAN::memory_order_release);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void __cxa_guard_abort (__guard*)
|
while (BAN::atomic_load(guard[1], BAN::memory_order_acquire))
|
||||||
{
|
Kernel::Processor::pause();
|
||||||
Kernel::panic("__cxa_guard_abort");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void __cxa_guard_release(uint64_t* g)
|
||||||
|
{
|
||||||
|
uint8_t* guard = reinterpret_cast<uint8_t*>(g);
|
||||||
|
BAN::atomic_store(guard[0], 1, BAN::memory_order_release);
|
||||||
|
BAN::atomic_store(guard[1], 0, BAN::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __cxa_guard_abort(uint64_t*)
|
||||||
|
{
|
||||||
|
Kernel::panic("__cxa_guard_abort");
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <kernel/ACPI/AML/Namespace.h>
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
#include <kernel/ACPI/EmbeddedController.h>
|
#include <kernel/ACPI/EmbeddedController.h>
|
||||||
#include <kernel/ACPI/Headers.h>
|
#include <kernel/ACPI/Headers.h>
|
||||||
|
#include <kernel/Interruptable.h>
|
||||||
#include <kernel/Memory/Types.h>
|
#include <kernel/Memory/Types.h>
|
||||||
#include <kernel/ThreadBlocker.h>
|
#include <kernel/ThreadBlocker.h>
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ namespace Kernel::ACPI
|
|||||||
|
|
||||||
BAN::ErrorOr<void> initialize_embedded_controller(const AML::Scope& embedded_controller);
|
BAN::ErrorOr<void> initialize_embedded_controller(const AML::Scope& embedded_controller);
|
||||||
BAN::ErrorOr<void> initialize_embedded_controllers();
|
BAN::ErrorOr<void> initialize_embedded_controllers();
|
||||||
|
void initialize_embedded_controller_gpes();
|
||||||
|
|
||||||
BAN::Optional<GAS> find_gpe_block(size_t index);
|
BAN::Optional<GAS> find_gpe_block(size_t index);
|
||||||
bool enable_gpe(uint8_t gpe);
|
bool enable_gpe(uint8_t gpe);
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Atomic.h>
|
#include <BAN/Atomic.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
#include <BAN/UniqPtr.h>
|
#include <BAN/UniqPtr.h>
|
||||||
|
|
||||||
#include <kernel/ACPI/AML/Scope.h>
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
#include <kernel/Lock/Mutex.h>
|
#include <kernel/Lock/Mutex.h>
|
||||||
#include <kernel/Thread.h>
|
#include <kernel/ThreadBlocker.h>
|
||||||
|
|
||||||
namespace Kernel::ACPI
|
namespace Kernel::ACPI
|
||||||
{
|
{
|
||||||
@@ -13,7 +14,7 @@ namespace Kernel::ACPI
|
|||||||
class EmbeddedController
|
class EmbeddedController
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<BAN::UniqPtr<EmbeddedController>> create(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, BAN::Optional<uint8_t> gpe);
|
static BAN::ErrorOr<BAN::UniqPtr<EmbeddedController>> create(AML::Scope&& scope, uint16_t command_port, uint16_t data_port);
|
||||||
~EmbeddedController();
|
~EmbeddedController();
|
||||||
|
|
||||||
BAN::ErrorOr<uint8_t> read_byte(uint8_t offset);
|
BAN::ErrorOr<uint8_t> read_byte(uint8_t offset);
|
||||||
@@ -21,21 +22,21 @@ namespace Kernel::ACPI
|
|||||||
|
|
||||||
const AML::Scope& scope() const { return m_scope; }
|
const AML::Scope& scope() const { return m_scope; }
|
||||||
|
|
||||||
|
static void handle_gpe_trampoline(void*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EmbeddedController(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, bool has_gpe)
|
EmbeddedController(AML::Scope&& scope, uint16_t command_port, uint16_t data_port)
|
||||||
: m_scope(BAN::move(scope))
|
: m_scope(BAN::move(scope))
|
||||||
, m_command_port(command_port)
|
, m_command_port(command_port)
|
||||||
, m_data_port(data_port)
|
, m_data_port(data_port)
|
||||||
, m_has_gpe(has_gpe)
|
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void wait_status_bit(uint8_t bit, uint8_t value);
|
void wait_status_bit(uint8_t mask, bool set);
|
||||||
|
|
||||||
uint8_t read_one(uint16_t port);
|
uint8_t read_one(uint16_t port);
|
||||||
void write_one(uint16_t port, uint8_t value);
|
void write_one(uint16_t port, uint8_t value);
|
||||||
|
|
||||||
static void handle_gpe_wrapper(void*);
|
|
||||||
void handle_gpe();
|
void handle_gpe();
|
||||||
|
|
||||||
BAN::ErrorOr<void> call_query_method(uint8_t notification);
|
BAN::ErrorOr<void> call_query_method(uint8_t notification);
|
||||||
@@ -56,7 +57,6 @@ namespace Kernel::ACPI
|
|||||||
const AML::Scope m_scope;
|
const AML::Scope m_scope;
|
||||||
const uint16_t m_command_port;
|
const uint16_t m_command_port;
|
||||||
const uint16_t m_data_port;
|
const uint16_t m_data_port;
|
||||||
const bool m_has_gpe;
|
|
||||||
|
|
||||||
Mutex m_mutex;
|
Mutex m_mutex;
|
||||||
ThreadBlocker m_thread_blocker;
|
ThreadBlocker m_thread_blocker;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
#include <kernel/InterruptController.h>
|
#include <kernel/InterruptController.h>
|
||||||
|
#include <kernel/InterruptNumbers.h>
|
||||||
#include <kernel/Lock/SpinLock.h>
|
#include <kernel/Lock/SpinLock.h>
|
||||||
#include <kernel/Memory/Types.h>
|
#include <kernel/Memory/Types.h>
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ namespace Kernel
|
|||||||
BAN::Vector<BAN::Vector<const HDAudio::AFGWidget*>> m_output_paths;
|
BAN::Vector<BAN::Vector<const HDAudio::AFGWidget*>> m_output_paths;
|
||||||
BAN::Vector<const HDAudio::AFGWidget*> m_output_pins;
|
BAN::Vector<const HDAudio::AFGWidget*> m_output_pins;
|
||||||
size_t m_output_path_index { SIZE_MAX };
|
size_t m_output_path_index { SIZE_MAX };
|
||||||
|
size_t m_amplifier_idx { SIZE_MAX };
|
||||||
|
|
||||||
uint8_t m_stream_id { 0xFF };
|
uint8_t m_stream_id { 0xFF };
|
||||||
uint8_t m_stream_index { 0xFF };
|
uint8_t m_stream_index { 0xFF };
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Optional.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
namespace Kernel::HDAudio
|
namespace Kernel::HDAudio
|
||||||
@@ -64,6 +65,7 @@ namespace Kernel::HDAudio
|
|||||||
};
|
};
|
||||||
|
|
||||||
BAN::Optional<Amplifier> output_amplifier;
|
BAN::Optional<Amplifier> output_amplifier;
|
||||||
|
BAN::Optional<Amplifier> input_amplifier;
|
||||||
|
|
||||||
BAN::Vector<uint16_t> connections;
|
BAN::Vector<uint16_t> connections;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,15 +6,22 @@
|
|||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class BGAController;
|
||||||
|
|
||||||
class FramebufferDevice : public CharacterDevice
|
class FramebufferDevice : public CharacterDevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> create(paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch, uint8_t bpp);
|
||||||
|
static BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> create(BAN::RefPtr<BGAController>);
|
||||||
static BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> create_from_boot_framebuffer();
|
static BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> create_from_boot_framebuffer();
|
||||||
static BAN::RefPtr<FramebufferDevice> boot_framebuffer();
|
static BAN::RefPtr<FramebufferDevice> boot_framebuffer();
|
||||||
~FramebufferDevice();
|
~FramebufferDevice();
|
||||||
|
|
||||||
uint32_t width() const { return m_width; }
|
uint32_t width() const { return m_width; }
|
||||||
uint32_t height() const { return m_height; }
|
uint32_t height() const { return m_height; }
|
||||||
|
uint8_t bpp() const { return m_bpp; }
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> set_bga_controller(BAN::RefPtr<BGAController>);
|
||||||
|
|
||||||
uint32_t get_pixel(uint32_t x, uint32_t y) const;
|
uint32_t get_pixel(uint32_t x, uint32_t y) const;
|
||||||
void set_pixel(uint32_t x, uint32_t y, uint32_t rgb);
|
void set_pixel(uint32_t x, uint32_t y, uint32_t rgb);
|
||||||
@@ -50,14 +57,16 @@ namespace Kernel
|
|||||||
private:
|
private:
|
||||||
const BAN::String m_name;
|
const BAN::String m_name;
|
||||||
|
|
||||||
vaddr_t m_video_memory_vaddr { 0 };
|
vaddr_t m_video_memory_vaddr { 0 };
|
||||||
const paddr_t m_video_memory_paddr;
|
paddr_t m_video_memory_paddr { 0 };
|
||||||
const uint32_t m_width;
|
|
||||||
const uint32_t m_height;
|
uint32_t m_width { 0 };
|
||||||
const uint32_t m_pitch;
|
uint32_t m_height { 0 };
|
||||||
const uint8_t m_bpp;
|
uint32_t m_pitch { 0 };
|
||||||
|
uint8_t m_bpp { 0 };
|
||||||
|
|
||||||
BAN::UniqPtr<VirtualRange> m_video_buffer;
|
BAN::UniqPtr<VirtualRange> m_video_buffer;
|
||||||
|
BAN::RefPtr<BGAController> m_bga_controller;
|
||||||
|
|
||||||
friend class FramebufferMemoryRegion;
|
friend class FramebufferMemoryRegion;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <BAN/HashMap.h>
|
#include <BAN/HashMap.h>
|
||||||
#include <kernel/FS/Inode.h>
|
#include <kernel/FS/Inode.h>
|
||||||
#include <kernel/Lock/Mutex.h>
|
#include <kernel/Lock/Mutex.h>
|
||||||
|
#include <kernel/ThreadBlocker.h>
|
||||||
|
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
#include <kernel/Device/Device.h>
|
|
||||||
#include <kernel/FS/TmpFS/FileSystem.h>
|
#include <kernel/FS/TmpFS/FileSystem.h>
|
||||||
#include <kernel/Lock/Mutex.h>
|
#include <kernel/Lock/Mutex.h>
|
||||||
#include <kernel/ThreadBlocker.h>
|
#include <kernel/ThreadBlocker.h>
|
||||||
@@ -9,6 +8,8 @@
|
|||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class Device;
|
||||||
|
|
||||||
class DevFileSystem final : public TmpFileSystem
|
class DevFileSystem final : public TmpFileSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <kernel/FS/Inode.h>
|
#include <kernel/FS/Inode.h>
|
||||||
#include <kernel/Lock/Mutex.h>
|
#include <kernel/Lock/Mutex.h>
|
||||||
|
#include <kernel/ThreadBlocker.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
@@ -22,16 +23,16 @@ namespace Kernel
|
|||||||
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||||
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||||
|
|
||||||
bool can_read_impl() const override { return m_value > 0; }
|
bool can_read_impl() const override;
|
||||||
bool can_write_impl() const override { return m_value < UINT64_MAX - 1; }
|
bool can_write_impl() const override;
|
||||||
bool has_error_impl() const override { return false; }
|
bool has_error_impl() const override { return false; }
|
||||||
bool has_hungup_impl() const override { return false; }
|
bool has_hungup_impl() const override { return false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const bool m_is_semaphore;
|
const bool m_is_semaphore;
|
||||||
BAN::Atomic<uint64_t> m_value;
|
uint64_t m_value;
|
||||||
|
|
||||||
Mutex m_mutex;
|
mutable Mutex m_mutex;
|
||||||
ThreadBlocker m_thread_blocker;
|
ThreadBlocker m_thread_blocker;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
#include <BAN/HashMap.h>
|
#include <BAN/HashMap.h>
|
||||||
#include <kernel/Device/Device.h>
|
#include <kernel/Device/Device.h>
|
||||||
#include <kernel/FS/FileSystem.h>
|
|
||||||
#include <kernel/FS/Ext2/Inode.h>
|
#include <kernel/FS/Ext2/Inode.h>
|
||||||
|
#include <kernel/FS/FileSystem.h>
|
||||||
|
#include <kernel/Memory/VirtualRange.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <kernel/FS/FAT/Definitions.h>
|
#include <kernel/FS/FAT/Definitions.h>
|
||||||
#include <kernel/FS/FAT/Inode.h>
|
#include <kernel/FS/FAT/Inode.h>
|
||||||
#include <kernel/FS/FileSystem.h>
|
#include <kernel/FS/FileSystem.h>
|
||||||
|
#include <kernel/Lock/Mutex.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kernel/Device/Device.h>
|
|
||||||
#include <kernel/FS/Inode.h>
|
#include <kernel/FS/Inode.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class BlockDevice;
|
||||||
|
|
||||||
class FileSystem : public BAN::RefCounted<FileSystem>
|
class FileSystem : public BAN::RefCounted<FileSystem>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
#include <kernel/FS/TmpFS/FileSystem.h>
|
#include <kernel/FS/TmpFS/FileSystem.h>
|
||||||
#include <kernel/FS/TmpFS/Inode.h>
|
#include <kernel/FS/TmpFS/Inode.h>
|
||||||
#include <kernel/Process.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class Process;
|
||||||
|
|
||||||
class ProcFileSystem final : public TmpFileSystem
|
class ProcFileSystem final : public TmpFileSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
#include <kernel/FS/TmpFS/FileSystem.h>
|
#include <kernel/FS/TmpFS/FileSystem.h>
|
||||||
#include <kernel/FS/TmpFS/Inode.h>
|
#include <kernel/FS/TmpFS/Inode.h>
|
||||||
#include <kernel/Process.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class Process;
|
||||||
|
|
||||||
class ProcPidInode final : public TmpDirectoryInode
|
class ProcPidInode final : public TmpDirectoryInode
|
||||||
{
|
{
|
||||||
// FIXME: dynamically update ruid/rgid.
|
// FIXME: dynamically update ruid/rgid.
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/RefPtr.h>
|
||||||
|
#include <kernel/Lock/SpinLock.h>
|
||||||
|
#include <kernel/PCI.h>
|
||||||
|
|
||||||
|
#include <sys/framebuffer.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class BGAController : public BAN::RefCounted<BGAController>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<BAN::RefPtr<BGAController>> create(PCI::Device&);
|
||||||
|
|
||||||
|
fb_fix_info get_fb_fix_info() const;
|
||||||
|
fb_var_info get_fb_var_info() const;
|
||||||
|
BAN::ErrorOr<void> set_fb_var_info(const fb_var_info&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BGAController(PCI::Device&);
|
||||||
|
BAN::ErrorOr<void> initialize();
|
||||||
|
|
||||||
|
void write_reg(uint16_t reg, uint16_t value);
|
||||||
|
uint16_t read_reg(uint16_t reg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable RecursiveSpinLock m_lock;
|
||||||
|
PCI::Device& m_pci_device;
|
||||||
|
BAN::UniqPtr<PCI::BarRegion> m_lfb_bar;
|
||||||
|
|
||||||
|
fb_fix_info m_fix_info {};
|
||||||
|
fb_var_info m_var_info {};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,21 +10,6 @@
|
|||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
// IDT entries
|
|
||||||
// 0x00->0x1F (32): ISR
|
|
||||||
// 0x20->0x7F (96): PIC/IOAPIC
|
|
||||||
// 0x80->0xEF (112): MSI
|
|
||||||
// 0xF0->0xFE (15): internal
|
|
||||||
|
|
||||||
constexpr uint8_t IRQ_VECTOR_BASE = 0x20;
|
|
||||||
constexpr uint8_t IRQ_MSI_BASE = 0x80;
|
|
||||||
constexpr uint8_t IRQ_MSI_END = 0xF0;
|
|
||||||
#if ARCH(i686)
|
|
||||||
constexpr uint8_t IRQ_SYSCALL = 0xF0; // hard coded in kernel/API/Syscall.h
|
|
||||||
#endif
|
|
||||||
constexpr uint8_t IRQ_IPI = 0xF1;
|
|
||||||
constexpr uint8_t IRQ_TIMER = 0xF2;
|
|
||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
struct GateDescriptor
|
struct GateDescriptor
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ namespace Kernel::Input
|
|||||||
uint8_t m_byte_index { 0 };
|
uint8_t m_byte_index { 0 };
|
||||||
bool m_basic { false };
|
bool m_basic { false };
|
||||||
|
|
||||||
|
bool m_scancode_set_uncertain { false };
|
||||||
uint8_t m_scancode_set { 0xFF };
|
uint8_t m_scancode_set { 0xFF };
|
||||||
uint16_t m_modifiers { 0 };
|
uint16_t m_modifiers { 0 };
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/Arch.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
// IDT entries
|
||||||
|
// 0x00->0x1F (32): ISR
|
||||||
|
// 0x20->0x7F (96): PIC/IOAPIC
|
||||||
|
// 0x80->0xEF (112): MSI
|
||||||
|
// 0xF0->0xFE (15): internal
|
||||||
|
|
||||||
|
constexpr uint8_t IRQ_VECTOR_BASE = 0x20;
|
||||||
|
constexpr uint8_t IRQ_MSI_BASE = 0x80;
|
||||||
|
constexpr uint8_t IRQ_MSI_END = 0xF0;
|
||||||
|
#if ARCH(i686)
|
||||||
|
constexpr uint8_t IRQ_SYSCALL = 0xF0; // hard coded in kernel/API/Syscall.h
|
||||||
|
#endif
|
||||||
|
constexpr uint8_t IRQ_IPI = 0xF1;
|
||||||
|
constexpr uint8_t IRQ_TIMER = 0xF2;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include <BAN/Atomic.h>
|
#include <BAN/Atomic.h>
|
||||||
#include <BAN/NoCopyMove.h>
|
#include <BAN/NoCopyMove.h>
|
||||||
#include <kernel/Thread.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
@@ -27,63 +26,14 @@ namespace Kernel
|
|||||||
public:
|
public:
|
||||||
Mutex() = default;
|
Mutex() = default;
|
||||||
|
|
||||||
void lock() override
|
bool try_lock();
|
||||||
{
|
void lock() override;
|
||||||
const auto tid = Thread::current_tid();
|
void unlock() override;
|
||||||
if (tid == m_locker)
|
|
||||||
ASSERT(m_lock_depth > 0);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ASSERT(!tid || !Thread::current().has_spinlock());
|
|
||||||
pid_t expected = -1;
|
|
||||||
while (!m_locker.compare_exchange(expected, tid))
|
|
||||||
{
|
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
|
||||||
Processor::yield();
|
|
||||||
expected = -1;
|
|
||||||
}
|
|
||||||
ASSERT(m_lock_depth == 0);
|
|
||||||
if (tid)
|
|
||||||
Thread::current().add_mutex();
|
|
||||||
}
|
|
||||||
m_lock_depth++;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool try_lock()
|
|
||||||
{
|
|
||||||
const auto tid = Thread::current_tid();
|
|
||||||
if (tid == m_locker)
|
|
||||||
ASSERT(m_lock_depth > 0);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pid_t expected = -1;
|
|
||||||
if (!m_locker.compare_exchange(expected, tid))
|
|
||||||
return false;
|
|
||||||
ASSERT(m_lock_depth == 0);
|
|
||||||
if (tid)
|
|
||||||
Thread::current().add_mutex();
|
|
||||||
}
|
|
||||||
m_lock_depth++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock() override
|
|
||||||
{
|
|
||||||
const auto tid = Thread::current_tid();
|
|
||||||
ASSERT(m_locker == tid);
|
|
||||||
ASSERT(m_lock_depth > 0);
|
|
||||||
if (--m_lock_depth == 0)
|
|
||||||
{
|
|
||||||
m_locker = -1;
|
|
||||||
if (tid)
|
|
||||||
Thread::current().remove_mutex();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_t locker() const { return m_locker; }
|
pid_t locker() const { return m_locker; }
|
||||||
bool is_locked() const { return m_locker != -1; }
|
bool is_locked() const { return m_locker != -1; }
|
||||||
uint32_t lock_depth() const override { return m_lock_depth; }
|
uint32_t lock_depth() const override { return m_lock_depth; }
|
||||||
bool is_locked_by_current_thread() const override { return m_locker == Thread::current_tid(); }
|
bool is_locked_by_current_thread() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BAN::Atomic<pid_t> m_locker { -1 };
|
BAN::Atomic<pid_t> m_locker { -1 };
|
||||||
@@ -98,74 +48,14 @@ namespace Kernel
|
|||||||
public:
|
public:
|
||||||
PriorityMutex() = default;
|
PriorityMutex() = default;
|
||||||
|
|
||||||
void lock() override
|
bool try_lock();
|
||||||
{
|
void lock() override;
|
||||||
const auto tid = Thread::current_tid();
|
void unlock() override;
|
||||||
|
|
||||||
if (tid == m_locker)
|
|
||||||
ASSERT(m_lock_depth > 0);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ASSERT(!tid || !Thread::current().has_spinlock());
|
|
||||||
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
|
||||||
if (has_priority)
|
|
||||||
m_queue_length++;
|
|
||||||
pid_t expected = -1;
|
|
||||||
while (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(expected, tid))
|
|
||||||
{
|
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
|
||||||
Processor::yield();
|
|
||||||
expected = -1;
|
|
||||||
}
|
|
||||||
ASSERT(m_lock_depth == 0);
|
|
||||||
if (tid)
|
|
||||||
Thread::current().add_mutex();
|
|
||||||
}
|
|
||||||
m_lock_depth++;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool try_lock()
|
|
||||||
{
|
|
||||||
const auto tid = Thread::current_tid();
|
|
||||||
|
|
||||||
if (tid == m_locker)
|
|
||||||
ASSERT(m_lock_depth > 0);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
|
||||||
pid_t expected = -1;
|
|
||||||
if (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(expected, tid))
|
|
||||||
return false;
|
|
||||||
if (has_priority)
|
|
||||||
m_queue_length++;
|
|
||||||
ASSERT(m_lock_depth == 0);
|
|
||||||
if (tid)
|
|
||||||
Thread::current().add_mutex();
|
|
||||||
}
|
|
||||||
m_lock_depth++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock() override
|
|
||||||
{
|
|
||||||
const auto tid = Thread::current_tid();
|
|
||||||
ASSERT(m_locker == tid);
|
|
||||||
ASSERT(m_lock_depth > 0);
|
|
||||||
if (--m_lock_depth == 0)
|
|
||||||
{
|
|
||||||
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
|
||||||
if (has_priority)
|
|
||||||
m_queue_length--;
|
|
||||||
m_locker = -1;
|
|
||||||
if (tid)
|
|
||||||
Thread::current().remove_mutex();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_t locker() const { return m_locker; }
|
pid_t locker() const { return m_locker; }
|
||||||
bool is_locked() const { return m_locker != -1; }
|
bool is_locked() const { return m_locker != -1; }
|
||||||
uint32_t lock_depth() const override { return m_lock_depth; }
|
uint32_t lock_depth() const override { return m_lock_depth; }
|
||||||
bool is_locked_by_current_thread() const override { return m_locker == Thread::current_tid(); }
|
bool is_locked_by_current_thread() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BAN::Atomic<pid_t> m_locker { -1 };
|
BAN::Atomic<pid_t> m_locker { -1 };
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kernel/Lock/BlockableSpinLock.h>
|
|
||||||
#include <kernel/Lock/SpinLock.h>
|
#include <kernel/Lock/SpinLock.h>
|
||||||
|
#include <kernel/ThreadBlocker.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
@@ -13,54 +13,10 @@ namespace Kernel
|
|||||||
public:
|
public:
|
||||||
RWLock() = default;
|
RWLock() = default;
|
||||||
|
|
||||||
void rd_lock()
|
void rd_lock();
|
||||||
{
|
void rd_unlock();
|
||||||
SpinLockGuard _(m_lock);
|
void wr_lock();
|
||||||
while (m_writers_waiting > 0 || m_writer != -1)
|
void wr_unlock();
|
||||||
{
|
|
||||||
BlockableSpinLock block(m_lock);
|
|
||||||
m_thread_blocker.block_indefinite(&block);
|
|
||||||
}
|
|
||||||
m_readers_active++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rd_unlock()
|
|
||||||
{
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
if (--m_readers_active == 0)
|
|
||||||
m_thread_blocker.unblock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void wr_lock()
|
|
||||||
{
|
|
||||||
if (m_writer == Thread::current_tid())
|
|
||||||
{
|
|
||||||
m_writer_depth++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
|
|
||||||
m_writers_waiting++;
|
|
||||||
while (m_readers_active > 0 || m_writer != -1)
|
|
||||||
{
|
|
||||||
BlockableSpinLock block(m_lock);
|
|
||||||
m_thread_blocker.block_indefinite(&block);
|
|
||||||
}
|
|
||||||
m_writers_waiting--;
|
|
||||||
|
|
||||||
m_writer = Thread::current_tid();
|
|
||||||
m_writer_depth = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wr_unlock()
|
|
||||||
{
|
|
||||||
if (--m_writer_depth != 0)
|
|
||||||
return;
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
m_writer = -1;
|
|
||||||
m_thread_blocker.unblock();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SpinLock m_lock;
|
SpinLock m_lock;
|
||||||
|
|||||||
@@ -61,9 +61,6 @@ namespace Kernel
|
|||||||
uint32_t m_lock_depth { 0 };
|
uint32_t m_lock_depth { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Lock>
|
|
||||||
class SpinLockGuardAsMutex;
|
|
||||||
|
|
||||||
template<typename Lock>
|
template<typename Lock>
|
||||||
class SpinLockGuard
|
class SpinLockGuard
|
||||||
{
|
{
|
||||||
@@ -85,7 +82,6 @@ namespace Kernel
|
|||||||
private:
|
private:
|
||||||
Lock& m_lock;
|
Lock& m_lock;
|
||||||
InterruptState m_state;
|
InterruptState m_state;
|
||||||
friend class SpinLockGuardAsMutex<Lock>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Vector.h>
|
||||||
#include <kernel/Memory/MemoryRegion.h>
|
#include <kernel/Memory/MemoryRegion.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/HashMap.h>
|
#include <BAN/HashMap.h>
|
||||||
|
#include <BAN/RefPtr.h>
|
||||||
#include <BAN/UniqPtr.h>
|
#include <BAN/UniqPtr.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
#include <kernel/Lock/Mutex.h>
|
#include <kernel/Lock/Mutex.h>
|
||||||
#include <kernel/Lock/SpinLock.h>
|
#include <kernel/Lock/SpinLock.h>
|
||||||
#include <kernel/Memory/MemoryRegion.h>
|
#include <kernel/Memory/MemoryRegion.h>
|
||||||
@@ -27,8 +29,9 @@ namespace Kernel
|
|||||||
private:
|
private:
|
||||||
struct Object : public BAN::RefCounted<Object>
|
struct Object : public BAN::RefCounted<Object>
|
||||||
{
|
{
|
||||||
Object(key_t key, shmid_ds info)
|
Object(key_t key, int id, shmid_ds info)
|
||||||
: key(key)
|
: key(key)
|
||||||
|
, id(id)
|
||||||
, info(info)
|
, info(info)
|
||||||
{ }
|
{ }
|
||||||
~Object();
|
~Object();
|
||||||
@@ -36,6 +39,7 @@ namespace Kernel
|
|||||||
bool can_current_process_access(int flags) const;
|
bool can_current_process_access(int flags) const;
|
||||||
|
|
||||||
const key_t key;
|
const key_t key;
|
||||||
|
const int id;
|
||||||
shmid_ds info;
|
shmid_ds info;
|
||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
#include <BAN/HashMap.h>
|
#include <BAN/HashMap.h>
|
||||||
#include <BAN/UniqPtr.h>
|
#include <BAN/UniqPtr.h>
|
||||||
#include <kernel/Networking/NetworkInterface.h>
|
#include <kernel/Networking/NetworkInterface.h>
|
||||||
#include <kernel/Thread.h>
|
|
||||||
#include <kernel/ThreadBlocker.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include <kernel/Networking/NetworkInterface.h>
|
#include <kernel/Networking/NetworkInterface.h>
|
||||||
#include <kernel/Networking/NetworkLayer.h>
|
#include <kernel/Networking/NetworkLayer.h>
|
||||||
#include <kernel/Networking/NetworkSocket.h>
|
#include <kernel/Networking/NetworkSocket.h>
|
||||||
#include <kernel/Thread.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kernel/Networking/NetworkInterface.h>
|
#include <kernel/Networking/NetworkInterface.h>
|
||||||
|
#include <kernel/Memory/VirtualRange.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include <kernel/Memory/ByteRingBuffer.h>
|
#include <kernel/Memory/ByteRingBuffer.h>
|
||||||
#include <kernel/Networking/NetworkInterface.h>
|
#include <kernel/Networking/NetworkInterface.h>
|
||||||
#include <kernel/Networking/NetworkSocket.h>
|
#include <kernel/Networking/NetworkSocket.h>
|
||||||
#include <kernel/Thread.h>
|
|
||||||
#include <kernel/ThreadBlocker.h>
|
#include <kernel/ThreadBlocker.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <kernel/FS/Socket.h>
|
#include <kernel/FS/Socket.h>
|
||||||
#include <kernel/FS/TmpFS/Inode.h>
|
#include <kernel/FS/TmpFS/Inode.h>
|
||||||
#include <kernel/FS/VirtualFileSystem.h>
|
#include <kernel/FS/VirtualFileSystem.h>
|
||||||
|
#include <kernel/Memory/VirtualRange.h>
|
||||||
#include <kernel/OpenFileDescriptorSet.h>
|
#include <kernel/OpenFileDescriptorSet.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
#include <BAN/UniqPtr.h>
|
#include <BAN/UniqPtr.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
#include <kernel/ACPI/AML/Node.h>
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/InterruptNumbers.h>
|
||||||
|
#include <kernel/Interruptable.h>
|
||||||
#include <kernel/Memory/Types.h>
|
#include <kernel/Memory/Types.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <sys/banan-os.h>
|
#include <sys/banan-os.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@@ -26,8 +27,6 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
|
||||||
struct epoll_event;
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -287,7 +286,7 @@ namespace Kernel
|
|||||||
BAN::ErrorOr<FileParent> find_parent_file(int fd, const char* path, int flags) const;
|
BAN::ErrorOr<FileParent> find_parent_file(int fd, const char* path, int flags) const;
|
||||||
BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const;
|
BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const;
|
||||||
|
|
||||||
BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write);
|
BAN::ErrorOr<void> validate_and_pin_pointer_access(const void*, size_t, bool needs_write, BAN::Vector<MemoryRegion*>&);
|
||||||
|
|
||||||
uint64_t signal_pending_mask() const
|
uint64_t signal_pending_mask() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Array.h>
|
||||||
#include <BAN/Atomic.h>
|
#include <BAN/Atomic.h>
|
||||||
#include <BAN/ForwardList.h>
|
#include <BAN/NoCopyMove.h>
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Math.h>
|
||||||
|
|
||||||
#include <kernel/API/SharedPage.h>
|
#include <kernel/API/SharedPage.h>
|
||||||
#include <kernel/Arch.h>
|
#include <kernel/Arch.h>
|
||||||
#include <kernel/GDT.h>
|
|
||||||
#include <kernel/IDT.h>
|
|
||||||
#include <kernel/InterruptStack.h>
|
|
||||||
#include <kernel/Memory/Types.h>
|
#include <kernel/Memory/Types.h>
|
||||||
#include <kernel/ProcessorID.h>
|
#include <kernel/ProcessorID.h>
|
||||||
#include <kernel/Scheduler.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
@@ -22,6 +19,11 @@ namespace Kernel
|
|||||||
Enabled,
|
Enabled,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GDT;
|
||||||
|
class IDT;
|
||||||
|
class Scheduler;
|
||||||
|
class Thread;
|
||||||
|
|
||||||
#if ARCH(x86_64) || ARCH(i686)
|
#if ARCH(x86_64) || ARCH(i686)
|
||||||
class Processor
|
class Processor
|
||||||
{
|
{
|
||||||
@@ -51,8 +53,8 @@ namespace Kernel
|
|||||||
union
|
union
|
||||||
{
|
{
|
||||||
TLBEntry flush_tlb;
|
TLBEntry flush_tlb;
|
||||||
SchedulerQueue::Node* new_thread;
|
Thread* new_thread;
|
||||||
SchedulerQueue::Node* unblock_thread;
|
Thread* unblock_thread;
|
||||||
bool dummy;
|
bool dummy;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -179,17 +181,23 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= 8 && BAN::Math::is_power_of_two(sizeof(T)))
|
static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= sizeof(uintptr_t) && BAN::Math::is_power_of_two(sizeof(T)))
|
||||||
{
|
{
|
||||||
T value;
|
T value;
|
||||||
asm volatile("mov %%gs:%a[offset], %[value]" : [value]"=r"(value) : [offset]"ir"(offset));
|
if constexpr (sizeof(T) == 1 && ARCH(i686))
|
||||||
|
asm volatile("mov %%gs:%a[offset], %[value]" : [value]"=q"(value) : [offset]"ir"(offset) : "memory");
|
||||||
|
else
|
||||||
|
asm volatile("mov %%gs:%a[offset], %[value]" : [value]"=r"(value) : [offset]"ir"(offset) : "memory");
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void write_gs_sized(uintptr_t offset, T value) requires(sizeof(T) <= 8 && BAN::Math::is_power_of_two(sizeof(T)))
|
static void write_gs_sized(uintptr_t offset, T value) requires(sizeof(T) <= sizeof(uintptr_t) && BAN::Math::is_power_of_two(sizeof(T)))
|
||||||
{
|
{
|
||||||
asm volatile("mov %[value], %%gs:%a[offset]" :: [value]"r"(value), [offset]"ir"(offset) : "memory");
|
if constexpr (sizeof(T) == 1 && ARCH(i686))
|
||||||
|
asm volatile("mov %[value], %%gs:%a[offset]" :: [value]"q"(value), [offset]"ir"(offset) : "memory");
|
||||||
|
else
|
||||||
|
asm volatile("mov %[value], %%gs:%a[offset]" :: [value]"r"(value), [offset]"ir"(offset) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
void lock_tlb_lock();
|
void lock_tlb_lock();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <BAN/NoCopyMove.h>
|
#include <BAN/NoCopyMove.h>
|
||||||
#include <kernel/InterruptStack.h>
|
#include <kernel/InterruptStack.h>
|
||||||
#include <kernel/ProcessorID.h>
|
#include <kernel/ProcessorID.h>
|
||||||
|
#include <kernel/SchedulerThreadNode.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
@@ -14,29 +15,6 @@ namespace Kernel
|
|||||||
class BaseMutex;
|
class BaseMutex;
|
||||||
class Thread;
|
class Thread;
|
||||||
class ThreadBlocker;
|
class ThreadBlocker;
|
||||||
struct SchedulerQueueNode;
|
|
||||||
|
|
||||||
class SchedulerQueue
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Node = SchedulerQueueNode;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void add_thread_to_back(Node*);
|
|
||||||
bool add_thread_with_wake_time(Node*); // return true if node was inserted as the first element
|
|
||||||
template<typename F>
|
|
||||||
Node* remove_with_condition(F callback);
|
|
||||||
void remove_node(Node*);
|
|
||||||
Node* front();
|
|
||||||
Node* pop_front();
|
|
||||||
|
|
||||||
bool empty() const { return m_head == nullptr; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Node* m_head { nullptr };
|
|
||||||
Node* m_tail { nullptr };
|
|
||||||
};
|
|
||||||
|
|
||||||
class Scheduler
|
class Scheduler
|
||||||
{
|
{
|
||||||
BAN_NON_COPYABLE(Scheduler);
|
BAN_NON_COPYABLE(Scheduler);
|
||||||
@@ -45,12 +23,12 @@ namespace Kernel
|
|||||||
public:
|
public:
|
||||||
struct NewThreadRequest
|
struct NewThreadRequest
|
||||||
{
|
{
|
||||||
SchedulerQueue::Node* node;
|
SchedulerThreadNode* node;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UnblockRequest
|
struct UnblockRequest
|
||||||
{
|
{
|
||||||
SchedulerQueue::Node* node;
|
SchedulerThreadNode* node;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -63,9 +41,8 @@ namespace Kernel
|
|||||||
void on_timer_interrupt();
|
void on_timer_interrupt();
|
||||||
void on_yield(YieldRegisters*);
|
void on_yield(YieldRegisters*);
|
||||||
|
|
||||||
static BAN::ErrorOr<void> bind_thread_to_processor(Thread*, ProcessorID);
|
static void bind_thread_to_processor(Thread*, ProcessorID);
|
||||||
// if thread is already bound, this will never fail
|
void add_thread(Thread*);
|
||||||
BAN::ErrorOr<void> add_thread(Thread*);
|
|
||||||
|
|
||||||
void block_current_thread(ThreadBlocker* thread_blocker, uint64_t wake_time_ns, BaseMutex* mutex);
|
void block_current_thread(ThreadBlocker* thread_blocker, uint64_t wake_time_ns, BaseMutex* mutex);
|
||||||
void unblock_thread(Thread*);
|
void unblock_thread(Thread*);
|
||||||
@@ -79,9 +56,9 @@ namespace Kernel
|
|||||||
private:
|
private:
|
||||||
Scheduler() = default;
|
Scheduler() = default;
|
||||||
|
|
||||||
void add_current_to_most_loaded(SchedulerQueue* target_queue);
|
void add_current_to_most_loaded(void* target_list);
|
||||||
void update_most_loaded_node_queue(SchedulerQueue::Node*, SchedulerQueue* target_queue);
|
void update_most_loaded_node_list(SchedulerThreadNode*, void* target_list);
|
||||||
void remove_node_from_most_loaded(SchedulerQueue::Node*);
|
void remove_node_from_most_loaded(SchedulerThreadNode*);
|
||||||
|
|
||||||
void update_wake_up_deadline();
|
void update_wake_up_deadline();
|
||||||
void wake_up_sleeping_threads();
|
void wake_up_sleeping_threads();
|
||||||
@@ -90,13 +67,10 @@ namespace Kernel
|
|||||||
|
|
||||||
class ProcessorID find_least_loaded_processor() const;
|
class ProcessorID find_least_loaded_processor() const;
|
||||||
|
|
||||||
void add_thread(SchedulerQueue::Node*);
|
|
||||||
void unblock_thread(SchedulerQueue::Node*);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SchedulerQueue m_run_queue;
|
SchedulerQueue m_run_list;
|
||||||
SchedulerQueue m_block_queue;
|
SchedulerHeap m_block_list;
|
||||||
SchedulerQueue::Node* m_current { nullptr };
|
SchedulerThreadNode* m_current { nullptr };
|
||||||
|
|
||||||
uint32_t m_thread_count { 0 };
|
uint32_t m_thread_count { 0 };
|
||||||
|
|
||||||
@@ -108,8 +82,8 @@ namespace Kernel
|
|||||||
|
|
||||||
struct ThreadInfo
|
struct ThreadInfo
|
||||||
{
|
{
|
||||||
SchedulerQueue* queue { nullptr };
|
void* list { nullptr };
|
||||||
SchedulerQueue::Node* node { nullptr };
|
SchedulerThreadNode* node { nullptr };
|
||||||
};
|
};
|
||||||
BAN::Array<ThreadInfo, 10> m_most_loaded_threads;
|
BAN::Array<ThreadInfo, 10> m_most_loaded_threads;
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <kernel/ProcessorID.h>
|
|
||||||
#include <kernel/Lock/SpinLock.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
|
||||||
{
|
|
||||||
|
|
||||||
class Thread;
|
|
||||||
class ThreadBlocker;
|
|
||||||
|
|
||||||
struct SchedulerQueueNode
|
|
||||||
{
|
|
||||||
SchedulerQueueNode(Thread* thread)
|
|
||||||
: thread(thread)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Thread* const thread;
|
|
||||||
|
|
||||||
SchedulerQueueNode* next { nullptr };
|
|
||||||
SchedulerQueueNode* prev { nullptr };
|
|
||||||
|
|
||||||
uint64_t wake_time_ns { static_cast<uint64_t>(-1) };
|
|
||||||
|
|
||||||
BAN::Atomic<ThreadBlocker*> blocker { nullptr };
|
|
||||||
SchedulerQueueNode* block_chain_prev { nullptr };
|
|
||||||
SchedulerQueueNode* block_chain_next { nullptr };
|
|
||||||
|
|
||||||
ProcessorID processor_id { PROCESSOR_NONE };
|
|
||||||
bool blocked { false };
|
|
||||||
|
|
||||||
uint64_t last_start_ns { 0 };
|
|
||||||
uint64_t time_used_ns { 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Atomic.h>
|
||||||
|
#include <BAN/NoCopyMove.h>
|
||||||
|
#include <kernel/ProcessorID.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class Thread;
|
||||||
|
class ThreadBlocker;
|
||||||
|
|
||||||
|
struct SchedulerThreadNode
|
||||||
|
{
|
||||||
|
SchedulerThreadNode(Thread* thread)
|
||||||
|
: thread(thread)
|
||||||
|
, heap({ nullptr, nullptr, nullptr })
|
||||||
|
{}
|
||||||
|
|
||||||
|
Thread* const thread;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SchedulerThreadNode* next;
|
||||||
|
SchedulerThreadNode* prev;
|
||||||
|
} queue;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SchedulerThreadNode* parent;
|
||||||
|
SchedulerThreadNode* lchild;
|
||||||
|
SchedulerThreadNode* rchild;
|
||||||
|
} heap;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint64_t wake_time_ns { static_cast<uint64_t>(-1) };
|
||||||
|
|
||||||
|
BAN::Atomic<ThreadBlocker*> blocker { nullptr };
|
||||||
|
SchedulerThreadNode* block_chain_prev { nullptr };
|
||||||
|
SchedulerThreadNode* block_chain_next { nullptr };
|
||||||
|
|
||||||
|
ProcessorID processor_id { PROCESSOR_NONE };
|
||||||
|
bool blocked { false };
|
||||||
|
|
||||||
|
uint64_t last_start_ns { 0 };
|
||||||
|
uint64_t time_used_ns { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
class SchedulerQueue
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(SchedulerQueue);
|
||||||
|
BAN_NON_MOVABLE(SchedulerQueue);
|
||||||
|
public:
|
||||||
|
SchedulerQueue() = default;
|
||||||
|
|
||||||
|
SchedulerThreadNode* front();
|
||||||
|
SchedulerThreadNode* pop_front();
|
||||||
|
|
||||||
|
void push(SchedulerThreadNode*);
|
||||||
|
void pop(SchedulerThreadNode*);
|
||||||
|
|
||||||
|
void walk(void (*)(const SchedulerThreadNode*, void*), void*) const;
|
||||||
|
bool empty() const { return m_head == nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SchedulerThreadNode* m_head { nullptr };
|
||||||
|
SchedulerThreadNode* m_tail { nullptr };
|
||||||
|
};
|
||||||
|
|
||||||
|
class SchedulerHeap
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(SchedulerHeap);
|
||||||
|
BAN_NON_MOVABLE(SchedulerHeap);
|
||||||
|
public:
|
||||||
|
SchedulerHeap() = default;
|
||||||
|
|
||||||
|
SchedulerThreadNode* front();
|
||||||
|
SchedulerThreadNode* pop_front();
|
||||||
|
|
||||||
|
void push(SchedulerThreadNode*);
|
||||||
|
void pop(SchedulerThreadNode*);
|
||||||
|
|
||||||
|
void walk(void (*)(const SchedulerThreadNode*, void*), void*) const;
|
||||||
|
bool empty() const { return m_root == nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void walk_impl(void (*)(const SchedulerThreadNode*, void*), void*, const SchedulerThreadNode*) const;
|
||||||
|
void swap_nodes(SchedulerThreadNode*, SchedulerThreadNode*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SchedulerThreadNode* m_root { nullptr };
|
||||||
|
SchedulerThreadNode* m_last { nullptr };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/WeakPtr.h>
|
#include <BAN/WeakPtr.h>
|
||||||
|
#include <kernel/Memory/VirtualRange.h>
|
||||||
#include <kernel/Terminal/TTY.h>
|
#include <kernel/Terminal/TTY.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ namespace Kernel
|
|||||||
|
|
||||||
virtual bool master_has_closed() const { return false; }
|
virtual bool master_has_closed() const { return false; }
|
||||||
|
|
||||||
|
virtual bool is_vtty() const { return false; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TTY(termios termios, mode_t mode, uid_t uid, gid_t gid);
|
TTY(termios termios, mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
|
||||||
@@ -100,9 +102,9 @@ namespace Kernel
|
|||||||
termios m_termios;
|
termios m_termios;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Mutex m_mutex;
|
Mutex m_input_mutex;
|
||||||
|
|
||||||
Mutex m_write_lock;
|
RecursiveSpinLock m_write_lock;
|
||||||
ThreadBlocker m_write_blocker;
|
ThreadBlocker m_write_blocker;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ namespace Kernel
|
|||||||
|
|
||||||
void clear() override;
|
void clear() override;
|
||||||
|
|
||||||
|
bool is_vtty() const override { return true; }
|
||||||
|
BAN::ErrorOr<void> set_terminal_driver(BAN::RefPtr<TerminalDriver>);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BAN::StringView name() const override { return m_name; }
|
BAN::StringView name() const override { return m_name; }
|
||||||
bool putchar_impl(uint8_t ch) override;
|
bool putchar_impl(uint8_t ch) override;
|
||||||
@@ -96,8 +99,6 @@ namespace Kernel
|
|||||||
uint32_t m_last_cursor_row { static_cast<uint32_t>(-1) };
|
uint32_t m_last_cursor_row { static_cast<uint32_t>(-1) };
|
||||||
uint32_t m_last_cursor_column { static_cast<uint32_t>(-1) };
|
uint32_t m_last_cursor_column { static_cast<uint32_t>(-1) };
|
||||||
|
|
||||||
const Palette& m_palette;
|
|
||||||
|
|
||||||
TerminalDriver::Color m_foreground;
|
TerminalDriver::Color m_foreground;
|
||||||
TerminalDriver::Color m_background;
|
TerminalDriver::Color m_background;
|
||||||
bool m_colors_inverted { false };
|
bool m_colors_inverted { false };
|
||||||
|
|||||||
@@ -5,8 +5,9 @@
|
|||||||
#include <BAN/RefPtr.h>
|
#include <BAN/RefPtr.h>
|
||||||
#include <BAN/UniqPtr.h>
|
#include <BAN/UniqPtr.h>
|
||||||
#include <kernel/InterruptStack.h>
|
#include <kernel/InterruptStack.h>
|
||||||
|
#include <kernel/Lock/Mutex.h>
|
||||||
#include <kernel/Memory/VirtualRange.h>
|
#include <kernel/Memory/VirtualRange.h>
|
||||||
#include <kernel/ThreadBlocker.h>
|
#include <kernel/SchedulerThreadNode.h>
|
||||||
|
|
||||||
#include <LibELF/AuxiliaryVector.h>
|
#include <LibELF/AuxiliaryVector.h>
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ namespace Kernel
|
|||||||
|
|
||||||
class MemoryBackedRegion;
|
class MemoryBackedRegion;
|
||||||
class Process;
|
class Process;
|
||||||
|
class ThreadBlocker;
|
||||||
|
|
||||||
class Thread
|
class Thread
|
||||||
{
|
{
|
||||||
@@ -124,10 +126,14 @@ namespace Kernel
|
|||||||
|
|
||||||
bool is_userspace() const { return m_is_userspace; }
|
bool is_userspace() const { return m_is_userspace; }
|
||||||
|
|
||||||
uint64_t cpu_time_ns() const;
|
uint64_t cpu_time_total_ns() const;
|
||||||
|
void cpu_time_ns(uint64_t& user_ns, uint64_t& system_ns) const;
|
||||||
void set_cpu_time_start();
|
void set_cpu_time_start();
|
||||||
void set_cpu_time_stop();
|
void set_cpu_time_stop();
|
||||||
|
|
||||||
|
void set_is_in_syscall(bool is_in_syscall);
|
||||||
|
bool is_in_syscall() const { return m_is_in_syscall; }
|
||||||
|
|
||||||
void update_processor_index_address();
|
void update_processor_index_address();
|
||||||
|
|
||||||
void set_fsbase(vaddr_t base) { m_fsbase = base; }
|
void set_fsbase(vaddr_t base) { m_fsbase = base; }
|
||||||
@@ -187,7 +193,7 @@ namespace Kernel
|
|||||||
vaddr_t m_fsbase { 0 };
|
vaddr_t m_fsbase { 0 };
|
||||||
vaddr_t m_gsbase { 0 };
|
vaddr_t m_gsbase { 0 };
|
||||||
|
|
||||||
SchedulerQueue::Node* m_scheduler_node { nullptr };
|
SchedulerThreadNode m_scheduler_node;
|
||||||
|
|
||||||
YieldRegisters m_yield_registers { };
|
YieldRegisters m_yield_registers { };
|
||||||
|
|
||||||
@@ -200,8 +206,10 @@ namespace Kernel
|
|||||||
static_assert(_SIGMAX < 64);
|
static_assert(_SIGMAX < 64);
|
||||||
|
|
||||||
mutable SpinLock m_cpu_time_lock;
|
mutable SpinLock m_cpu_time_lock;
|
||||||
uint64_t m_cpu_time_ns { 0 };
|
uint64_t m_cpu_time_user_ns { 0 };
|
||||||
|
uint64_t m_cpu_time_system_ns { 0 };
|
||||||
uint64_t m_cpu_time_start_ns { UINT64_MAX };
|
uint64_t m_cpu_time_start_ns { UINT64_MAX };
|
||||||
|
BAN::Atomic<bool> m_is_in_syscall { false };
|
||||||
|
|
||||||
BAN::Atomic<uint32_t> m_spinlock_count { 0 };
|
BAN::Atomic<uint32_t> m_spinlock_count { 0 };
|
||||||
BAN::Atomic<uint32_t> m_mutex_count { 0 };
|
BAN::Atomic<uint32_t> m_mutex_count { 0 };
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Math.h>
|
||||||
|
#include <kernel/Lock/Mutex.h>
|
||||||
#include <kernel/Lock/SpinLock.h>
|
#include <kernel/Lock/SpinLock.h>
|
||||||
#include <kernel/Scheduler.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class SchedulerThreadNode;
|
||||||
|
|
||||||
class ThreadBlocker
|
class ThreadBlocker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -27,11 +29,11 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void add_thread_to_block_queue(SchedulerQueue::Node*);
|
void add_thread_to_block_queue(SchedulerThreadNode*);
|
||||||
void remove_thread_from_block_queue(SchedulerQueue::Node*);
|
void remove_thread_from_block_queue(SchedulerThreadNode*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SchedulerQueue::Node* m_block_chain { nullptr };
|
SchedulerThreadNode* m_block_chain { nullptr };
|
||||||
SpinLock m_lock;
|
SpinLock m_lock;
|
||||||
|
|
||||||
friend class Scheduler;
|
friend class Scheduler;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace Kernel
|
|||||||
Hub = 0x09,
|
Hub = 0x09,
|
||||||
BillboardDeviceClass = 0x11,
|
BillboardDeviceClass = 0x11,
|
||||||
DiagnosticDevice = 0xDC,
|
DiagnosticDevice = 0xDC,
|
||||||
|
WirelessController = 0xE0,
|
||||||
Miscellaneous = 0xEF,
|
Miscellaneous = 0xEF,
|
||||||
VendorSpecific = 0xFF,
|
VendorSpecific = 0xFF,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ namespace Kernel
|
|||||||
|
|
||||||
virtual void handle_stall(uint8_t endpoint_id) = 0;
|
virtual void handle_stall(uint8_t endpoint_id) = 0;
|
||||||
virtual void handle_input_data(size_t byte_count, uint8_t endpoint_id) = 0;
|
virtual void handle_input_data(size_t byte_count, uint8_t endpoint_id) = 0;
|
||||||
|
|
||||||
|
virtual bool is_hid_driver() const { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class USBDevice
|
class USBDevice
|
||||||
@@ -62,6 +64,12 @@ namespace Kernel
|
|||||||
uint8_t tt_think_time;
|
uint8_t tt_think_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct HIDInfo
|
||||||
|
{
|
||||||
|
BAN::Atomic<uint32_t> led_mask { 0 };
|
||||||
|
BAN::Vector<USBClassDriver*> led_controls;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
USBDevice(USBController& controller, USB::SpeedClass speed_class, uint8_t depth)
|
USBDevice(USBController& controller, USB::SpeedClass speed_class, uint8_t depth)
|
||||||
: m_controller(controller)
|
: m_controller(controller)
|
||||||
@@ -92,6 +100,8 @@ namespace Kernel
|
|||||||
void register_hub_to_init() { m_controller.register_hub_to_init(m_depth + 1); };
|
void register_hub_to_init() { m_controller.register_hub_to_init(m_depth + 1); };
|
||||||
void mark_hub_init_done() { m_controller.mark_hub_init_done(m_depth + 1); };
|
void mark_hub_init_done() { m_controller.mark_hub_init_done(m_depth + 1); };
|
||||||
|
|
||||||
|
void update_led_mask(uint32_t led_mask);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void handle_stall(uint8_t endpoint_id);
|
void handle_stall(uint8_t endpoint_id);
|
||||||
void handle_input_data(size_t byte_count, uint8_t endpoint_id);
|
void handle_input_data(size_t byte_count, uint8_t endpoint_id);
|
||||||
@@ -112,6 +122,7 @@ namespace Kernel
|
|||||||
BAN::UniqPtr<DMARegion> m_dma_buffer;
|
BAN::UniqPtr<DMARegion> m_dma_buffer;
|
||||||
|
|
||||||
BAN::Vector<BAN::UniqPtr<USBClassDriver>> m_class_drivers;
|
BAN::Vector<BAN::UniqPtr<USBClassDriver>> m_class_drivers;
|
||||||
|
HIDInfo m_hid_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ namespace Kernel
|
|||||||
struct DeviceReport
|
struct DeviceReport
|
||||||
{
|
{
|
||||||
BAN::Vector<USBHID::Report> inputs;
|
BAN::Vector<USBHID::Report> inputs;
|
||||||
|
BAN::Vector<USBHID::Report> outputs;
|
||||||
BAN::RefPtr<USBHIDDevice> device;
|
BAN::RefPtr<USBHIDDevice> device;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -81,27 +82,43 @@ namespace Kernel
|
|||||||
void handle_stall(uint8_t endpoint_id) override;
|
void handle_stall(uint8_t endpoint_id) override;
|
||||||
void handle_input_data(size_t byte_count, uint8_t endpoint_id) override;
|
void handle_input_data(size_t byte_count, uint8_t endpoint_id) override;
|
||||||
|
|
||||||
|
bool is_hid_driver() const override { return true; }
|
||||||
|
|
||||||
USBDevice& device() { return m_device; }
|
USBDevice& device() { return m_device; }
|
||||||
const USBDevice::InterfaceDescriptor& interface() const { return m_interface; }
|
const USBDevice::InterfaceDescriptor& interface() const { return m_interface; }
|
||||||
|
|
||||||
|
bool has_led_control() const { return !m_led_controls.empty(); }
|
||||||
|
void set_leds(uint32_t led_mask);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
USBHIDDriver(USBDevice&, const USBDevice::InterfaceDescriptor&);
|
USBHIDDriver(USBDevice&, const USBDevice::InterfaceDescriptor&);
|
||||||
~USBHIDDriver();
|
~USBHIDDriver();
|
||||||
|
|
||||||
BAN::ErrorOr<void> initialize() override;
|
BAN::ErrorOr<void> initialize() override;
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::Vector<DeviceReport>> initializes_device_reports(const BAN::Vector<USBHID::Collection>&);
|
BAN::ErrorOr<void> initializes_device_reports(const BAN::Vector<USBHID::Collection>&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct LEDControl
|
||||||
|
{
|
||||||
|
DeviceReport* report;
|
||||||
|
uint32_t report_id;
|
||||||
|
uint32_t report_bits;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
USBDevice& m_device;
|
USBDevice& m_device;
|
||||||
USBDevice::InterfaceDescriptor m_interface;
|
USBDevice::InterfaceDescriptor m_interface;
|
||||||
|
|
||||||
bool m_uses_report_id { false };
|
bool m_uses_report_id { false };
|
||||||
BAN::Vector<DeviceReport> m_device_inputs;
|
BAN::Vector<DeviceReport> m_device_reports;
|
||||||
|
|
||||||
uint8_t m_data_endpoint_id = 0;
|
uint8_t m_data_endpoint_id = 0;
|
||||||
BAN::UniqPtr<DMARegion> m_data_buffer;
|
BAN::UniqPtr<DMARegion> m_data_buffer;
|
||||||
|
|
||||||
|
BAN::Vector<LEDControl> m_led_controls;
|
||||||
|
BAN::UniqPtr<DMARegion> m_led_region;
|
||||||
|
|
||||||
friend class BAN::UniqPtr<USBHIDDriver>;
|
friend class BAN::UniqPtr<USBHIDDriver>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ namespace Kernel
|
|||||||
BAN_NON_MOVABLE(USBKeyboard);
|
BAN_NON_MOVABLE(USBKeyboard);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BAN::ErrorOr<void> initialize() override;
|
|
||||||
|
|
||||||
void start_report() override;
|
void start_report() override;
|
||||||
void stop_report() override;
|
void stop_report() override;
|
||||||
|
|
||||||
@@ -23,12 +21,9 @@ namespace Kernel
|
|||||||
void update() override;
|
void update() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
USBKeyboard(USBHIDDriver& driver, BAN::Vector<USBHID::Report>&& outputs);
|
USBKeyboard(USBHIDDriver& driver);
|
||||||
~USBKeyboard() = default;
|
~USBKeyboard() = default;
|
||||||
|
|
||||||
void set_leds(uint16_t mask);
|
|
||||||
void set_leds(uint8_t report_id, uint16_t mask);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
USBHIDDriver& m_driver;
|
USBHIDDriver& m_driver;
|
||||||
|
|
||||||
@@ -38,11 +33,7 @@ namespace Kernel
|
|||||||
BAN::Array<bool, 0x100> m_keyboard_state { false };
|
BAN::Array<bool, 0x100> m_keyboard_state { false };
|
||||||
BAN::Array<bool, 0x100> m_keyboard_state_temp { false };
|
BAN::Array<bool, 0x100> m_keyboard_state_temp { false };
|
||||||
uint16_t m_toggle_mask { 0 };
|
uint16_t m_toggle_mask { 0 };
|
||||||
|
|
||||||
uint16_t m_led_mask { 0 };
|
uint16_t m_led_mask { 0 };
|
||||||
BAN::UniqPtr<DMARegion> m_led_region;
|
|
||||||
|
|
||||||
BAN::Vector<USBHID::Report> m_outputs;
|
|
||||||
|
|
||||||
BAN::Optional<uint8_t> m_repeat_scancode;
|
BAN::Optional<uint8_t> m_repeat_scancode;
|
||||||
uint8_t m_repeat_modifier { 0 };
|
uint8_t m_repeat_modifier { 0 };
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kernel/Process.h>
|
|
||||||
#include <kernel/USB/Device.h>
|
#include <kernel/USB/Device.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
|
|||||||
@@ -373,6 +373,33 @@ namespace Kernel::XHCI
|
|||||||
uint32_t slot_id : 8;
|
uint32_t slot_id : 8;
|
||||||
} configure_endpoint_command;
|
} configure_endpoint_command;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32_t : 32;
|
||||||
|
uint32_t : 32;
|
||||||
|
uint32_t : 32;
|
||||||
|
uint32_t cycle_bit : 1;
|
||||||
|
uint32_t : 8;
|
||||||
|
uint32_t tsp : 1;
|
||||||
|
uint32_t trb_type : 6;
|
||||||
|
uint32_t endpoint_id : 5;
|
||||||
|
uint32_t : 3;
|
||||||
|
uint32_t slot_id : 8;
|
||||||
|
} reset_endpoint_command;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint64_t new_tr_deque_pointer : 64;
|
||||||
|
uint32_t : 16;
|
||||||
|
uint32_t stream_id : 16;
|
||||||
|
uint32_t cycle_bit : 1;
|
||||||
|
uint32_t : 9;
|
||||||
|
uint32_t trb_type : 6;
|
||||||
|
uint32_t endpoint_id : 5;
|
||||||
|
uint32_t : 3;
|
||||||
|
uint32_t slot_id : 8;
|
||||||
|
} set_tr_deque_pointer_command;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
uint64_t ring_segment_ponter : 64;
|
uint64_t ring_segment_ponter : 64;
|
||||||
|
|||||||
+82
-72
@@ -8,6 +8,7 @@
|
|||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
#include <kernel/Process.h>
|
#include <kernel/Process.h>
|
||||||
|
#include <kernel/Scheduler.h>
|
||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
#define RSPD_SIZE 20
|
#define RSPD_SIZE 20
|
||||||
@@ -783,30 +784,10 @@ acpi_release_global_lock:
|
|||||||
|
|
||||||
BAN::ErrorOr<void> ACPI::initialize_embedded_controller(const AML::Scope& embedded_controller)
|
BAN::ErrorOr<void> ACPI::initialize_embedded_controller(const AML::Scope& embedded_controller)
|
||||||
{
|
{
|
||||||
BAN::Optional<uint8_t> gpe_int;
|
|
||||||
|
|
||||||
do {
|
|
||||||
auto [gpe_path, gpe_obj] = TRY(m_namespace->find_named_object(embedded_controller, TRY(AML::NameString::from_string("_GPE"_sv)), true));
|
|
||||||
if (gpe_obj == nullptr)
|
|
||||||
{
|
|
||||||
dwarnln("EC {} does have _GPE", embedded_controller);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto gpe = TRY(AML::evaluate_node(gpe_path, gpe_obj->node));
|
|
||||||
if (gpe.type == AML::Node::Type::Package)
|
|
||||||
{
|
|
||||||
dwarnln("TODO: EC {} has package _GPE");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpe_int = TRY(AML::convert_node(BAN::move(gpe), AML::ConvInteger, -1)).as.integer.value;
|
|
||||||
} while (false);
|
|
||||||
|
|
||||||
auto [crs_path, crs_obj] = TRY(m_namespace->find_named_object(embedded_controller, TRY(AML::NameString::from_string("_CRS"_sv)), true));
|
auto [crs_path, crs_obj] = TRY(m_namespace->find_named_object(embedded_controller, TRY(AML::NameString::from_string("_CRS"_sv)), true));
|
||||||
if (crs_obj == nullptr)
|
if (crs_obj == nullptr)
|
||||||
{
|
{
|
||||||
dwarnln("EC {} does have _CRS", embedded_controller);
|
dwarnln("EC {} does not have _CRS", embedded_controller);
|
||||||
return BAN::Error::from_errno(ENOENT);
|
return BAN::Error::from_errno(ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -856,7 +837,7 @@ acpi_release_global_lock:
|
|||||||
const auto data_port = TRY(extract_io_port(crs_buffer));
|
const auto data_port = TRY(extract_io_port(crs_buffer));
|
||||||
const auto command_port = TRY(extract_io_port(crs_buffer));
|
const auto command_port = TRY(extract_io_port(crs_buffer));
|
||||||
|
|
||||||
TRY(m_embedded_controllers.push_back(TRY(EmbeddedController::create(TRY(embedded_controller.copy()), command_port, data_port, gpe_int))));
|
TRY(m_embedded_controllers.push_back(TRY(EmbeddedController::create(TRY(embedded_controller.copy()), command_port, data_port))));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -876,6 +857,33 @@ acpi_release_global_lock:
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ACPI::initialize_embedded_controller_gpes()
|
||||||
|
{
|
||||||
|
const auto initialize_gpe = [this](EmbeddedController& embedded_controller) -> BAN::ErrorOr<void> {
|
||||||
|
auto [gpe_path, gpe_obj] = TRY(m_namespace->find_named_object(embedded_controller.scope(), TRY(AML::NameString::from_string("_GPE"_sv)), true));
|
||||||
|
if (gpe_obj == nullptr)
|
||||||
|
{
|
||||||
|
dprintln("EC {} does not have _GPE", embedded_controller.scope());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto gpe = TRY(AML::evaluate_node(gpe_path, gpe_obj->node));
|
||||||
|
if (gpe.type == AML::Node::Type::Package)
|
||||||
|
{
|
||||||
|
dwarnln("TODO: EC {} has package _GPE");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto gpe_int = TRY(AML::convert_node(BAN::move(gpe), AML::ConvInteger, -1)).as.integer.value;
|
||||||
|
TRY(register_gpe_handler(gpe_int, &EmbeddedController::handle_gpe_trampoline, &embedded_controller));
|
||||||
|
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto& embedded_controller : m_embedded_controllers)
|
||||||
|
(void)initialize_gpe(*embedded_controller);
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> ACPI::register_gpe_handler(uint8_t gpe, void (*callback)(void*), void* argument)
|
BAN::ErrorOr<void> ACPI::register_gpe_handler(uint8_t gpe, void (*callback)(void*), void* argument)
|
||||||
{
|
{
|
||||||
if (m_gpe_methods[gpe].method)
|
if (m_gpe_methods[gpe].method)
|
||||||
@@ -995,57 +1003,27 @@ acpi_release_global_lock:
|
|||||||
// FIXME: add support for GPE blocks inside the ACPI namespace
|
// FIXME: add support for GPE blocks inside the ACPI namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto ret = initialize_embedded_controllers(); ret.is_error())
|
|
||||||
dwarnln("Failed to initialize Embedded Controllers: {}", ret.error());
|
|
||||||
|
|
||||||
if (auto ret = m_namespace->post_load_initialize(); ret.is_error())
|
|
||||||
dwarnln("Failed to initialize ACPI namespace: {}", ret.error());
|
|
||||||
|
|
||||||
auto [pic_path, pic_obj] = TRY(m_namespace->find_named_object({}, TRY(AML::NameString::from_string("\\_PIC"_sv))));
|
|
||||||
if (pic_obj && pic_obj->node.type == AML::Node::Type::Method)
|
|
||||||
{
|
|
||||||
auto& pic_node = pic_obj->node;
|
|
||||||
if (pic_node.as.method.arg_count != 1)
|
|
||||||
{
|
|
||||||
dwarnln("Method \\_PIC has {} arguments, expected 1", pic_node.as.method.arg_count);
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
AML::Reference arg_ref;
|
|
||||||
arg_ref.node.type = AML::Node::Type::Integer;
|
|
||||||
arg_ref.node.as.integer.value = InterruptController::get().is_using_apic() ? 1 : 0;
|
|
||||||
arg_ref.ref_count = 2;
|
|
||||||
|
|
||||||
BAN::Array<AML::Reference*, 7> arguments(nullptr);
|
|
||||||
arguments[0] = &arg_ref; // method call should not delete argument
|
|
||||||
TRY(AML::method_call(pic_path, pic_node, BAN::move(arguments)));
|
|
||||||
}
|
|
||||||
|
|
||||||
dprintln("Evaluated \\_PIC({})", InterruptController::get().is_using_apic() ? 1 : 0);
|
|
||||||
|
|
||||||
uint8_t irq = fadt().sci_int;
|
uint8_t irq = fadt().sci_int;
|
||||||
if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error())
|
if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error())
|
||||||
dwarnln("Could not enable ACPI interrupt: {}", ret.error());
|
dwarnln("Could not enable ACPI interrupt: {}", ret.error());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto hex_sv_to_int =
|
const auto hex_sv_to_int = [](BAN::StringView sv) -> BAN::Optional<uint32_t> {
|
||||||
[](BAN::StringView sv) -> BAN::Optional<uint32_t>
|
uint32_t ret = 0;
|
||||||
|
for (char c : sv)
|
||||||
{
|
{
|
||||||
uint32_t ret = 0;
|
ret <<= 4;
|
||||||
for (char c : sv)
|
if (c >= '0' && c <= '9')
|
||||||
{
|
ret += c - '0';
|
||||||
ret <<= 4;
|
else if (c >= 'A' && c <= 'F')
|
||||||
if (c >= '0' && c <= '9')
|
ret += c - 'A' + 10;
|
||||||
ret += c - '0';
|
else if (c >= 'a' && c <= 'f')
|
||||||
else if (c >= 'A' && c <= 'F')
|
ret += c - 'a' + 10;
|
||||||
ret += c - 'A' + 10;
|
else
|
||||||
else if (c >= 'a' && c <= 'f')
|
return {};
|
||||||
ret += c - 'a' + 10;
|
}
|
||||||
else
|
return ret;
|
||||||
return {};
|
};
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto [gpe_scope, gpe_obj] = TRY(m_namespace->find_named_object({}, TRY(AML::NameString::from_string("\\_GPE"))));
|
auto [gpe_scope, gpe_obj] = TRY(m_namespace->find_named_object({}, TRY(AML::NameString::from_string("\\_GPE"))));
|
||||||
if (gpe_obj && gpe_obj->node.is_scope())
|
if (gpe_obj && gpe_obj->node.is_scope())
|
||||||
@@ -1091,11 +1069,43 @@ acpi_release_global_lock:
|
|||||||
|
|
||||||
if (auto thread_or_error = Thread::create_kernel([](void*) { get().acpi_event_task(); }, nullptr); thread_or_error.is_error())
|
if (auto thread_or_error = Thread::create_kernel([](void*) { get().acpi_event_task(); }, nullptr); thread_or_error.is_error())
|
||||||
dwarnln("Failed to create ACPI thread, power button will not work: {}", thread_or_error.error());
|
dwarnln("Failed to create ACPI thread, power button will not work: {}", thread_or_error.error());
|
||||||
else if (auto ret = Processor::scheduler().add_thread(thread_or_error.value()); ret.is_error())
|
else
|
||||||
dwarnln("Failed to create ACPI thread, power button will not work: {}", ret.error());
|
{
|
||||||
|
Processor::scheduler().add_thread(thread_or_error.value());
|
||||||
|
dprintln("Initialized ACPI interrupts");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintln("Initialized ACPI interrupts");
|
if (auto ret = initialize_embedded_controllers(); ret.is_error())
|
||||||
|
dwarnln("Failed to initialize Embedded Controllers: {}", ret.error());
|
||||||
|
|
||||||
|
if (auto ret = m_namespace->post_load_initialize(); ret.is_error())
|
||||||
|
dwarnln("Failed to initialize ACPI namespace: {}", ret.error());
|
||||||
|
|
||||||
|
// NOTE: We cannot initialize EC GPEs before the post init is done, but post init does need ECs initialized
|
||||||
|
initialize_embedded_controller_gpes();
|
||||||
|
|
||||||
|
auto [pic_path, pic_obj] = TRY(m_namespace->find_named_object({}, TRY(AML::NameString::from_string("\\_PIC"_sv))));
|
||||||
|
if (pic_obj && pic_obj->node.type == AML::Node::Type::Method)
|
||||||
|
{
|
||||||
|
auto& pic_node = pic_obj->node;
|
||||||
|
if (pic_node.as.method.arg_count != 1)
|
||||||
|
{
|
||||||
|
dwarnln("Method \\_PIC has {} arguments, expected 1", pic_node.as.method.arg_count);
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
AML::Reference arg_ref;
|
||||||
|
arg_ref.node.type = AML::Node::Type::Integer;
|
||||||
|
arg_ref.node.as.integer.value = InterruptController::get().is_using_apic() ? 1 : 0;
|
||||||
|
arg_ref.ref_count = 2;
|
||||||
|
|
||||||
|
BAN::Array<AML::Reference*, 7> arguments(nullptr);
|
||||||
|
arguments[0] = &arg_ref; // method call should not delete argument
|
||||||
|
TRY(AML::method_call(pic_path, pic_node, BAN::move(arguments)));
|
||||||
|
|
||||||
|
dprintln("Evaluated \\_PIC({})", InterruptController::get().is_using_apic() ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (InterruptController::get().is_using_apic())
|
if (InterruptController::get().is_using_apic())
|
||||||
{
|
{
|
||||||
@@ -1198,6 +1208,8 @@ acpi_release_global_lock:
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
handle_event:
|
handle_event:
|
||||||
|
IO::outw(sts_port, pending);
|
||||||
|
|
||||||
if (pending & PM1_EVN_PWRBTN)
|
if (pending & PM1_EVN_PWRBTN)
|
||||||
{
|
{
|
||||||
dprintln("Power button pressed");
|
dprintln("Power button pressed");
|
||||||
@@ -1208,8 +1220,6 @@ handle_event:
|
|||||||
{
|
{
|
||||||
dwarnln("Unhandled ACPI fixed event {H}", pending);
|
dwarnln("Unhandled ACPI fixed event {H}", pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
IO::outw(sts_port, pending);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -494,8 +494,23 @@ namespace Kernel::ACPI::AML
|
|||||||
|
|
||||||
return TRY(embedded_controller->read_byte(offset));
|
return TRY(embedded_controller->read_byte(offset));
|
||||||
}
|
}
|
||||||
case GAS::AddressSpaceID::SMBus:
|
|
||||||
case GAS::AddressSpaceID::SystemCMOS:
|
case GAS::AddressSpaceID::SystemCMOS:
|
||||||
|
if (byte_offset >= 64)
|
||||||
|
{
|
||||||
|
dwarnln("CMOS read from offset 0x{H}", byte_offset);
|
||||||
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
}
|
||||||
|
switch (access_size)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
IO::outb(0x70, offset);
|
||||||
|
return IO::inb(0x71);
|
||||||
|
default:
|
||||||
|
dwarnln("{} byte read from CMOS offset {2H}", access_size, byte_offset);
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
case GAS::AddressSpaceID::SMBus:
|
||||||
case GAS::AddressSpaceID::PCIBarTarget:
|
case GAS::AddressSpaceID::PCIBarTarget:
|
||||||
case GAS::AddressSpaceID::IPMI:
|
case GAS::AddressSpaceID::IPMI:
|
||||||
case GAS::AddressSpaceID::GeneralPurposeIO:
|
case GAS::AddressSpaceID::GeneralPurposeIO:
|
||||||
@@ -581,8 +596,24 @@ namespace Kernel::ACPI::AML
|
|||||||
TRY(embedded_controller->write_byte(offset, value));
|
TRY(embedded_controller->write_byte(offset, value));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
case GAS::AddressSpaceID::SMBus:
|
|
||||||
case GAS::AddressSpaceID::SystemCMOS:
|
case GAS::AddressSpaceID::SystemCMOS:
|
||||||
|
if (byte_offset >= 64)
|
||||||
|
{
|
||||||
|
dwarnln("CMOS write to offset 0x{H}", byte_offset);
|
||||||
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
}
|
||||||
|
switch (access_size)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
IO::outb(0x70, offset);
|
||||||
|
IO::outb(0x71, value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dwarnln("{} byte write to CMOS offset {2H}", access_size, byte_offset);
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
case GAS::AddressSpaceID::SMBus:
|
||||||
case GAS::AddressSpaceID::PCIBarTarget:
|
case GAS::AddressSpaceID::PCIBarTarget:
|
||||||
case GAS::AddressSpaceID::IPMI:
|
case GAS::AddressSpaceID::IPMI:
|
||||||
case GAS::AddressSpaceID::GeneralPurposeIO:
|
case GAS::AddressSpaceID::GeneralPurposeIO:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <kernel/ACPI/BatterySystem.h>
|
#include <kernel/ACPI/BatterySystem.h>
|
||||||
#include <kernel/FS/DevFS//FileSystem.h>
|
#include <kernel/Device/Device.h>
|
||||||
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
namespace Kernel::ACPI
|
namespace Kernel::ACPI
|
||||||
@@ -35,34 +36,11 @@ namespace Kernel::ACPI
|
|||||||
if (offset < 0)
|
if (offset < 0)
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
if (SystemTimer::get().ms_since_boot() > m_last_read_ms + 1000)
|
auto target_str = TRY(BAN::String::formatted("{}", TRY(get_value())));
|
||||||
{
|
|
||||||
auto [method_path, method_ref] = TRY(m_acpi_namespace.find_named_object(m_battery_path, m_method_name));
|
|
||||||
if (method_ref == nullptr)
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
auto result = TRY(AML::method_call(method_path, method_ref->node, BAN::Array<AML::Reference*, 7>{}));
|
|
||||||
if (result.type != AML::Node::Type::Package || result.as.package->num_elements < m_result_index)
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
auto& target_elem = result.as.package->elements[m_result_index];
|
|
||||||
if (!target_elem.resolved || !target_elem.value.node)
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
auto target_conv = AML::convert_node(TRY(target_elem.value.node->copy()), AML::ConvInteger, sizeof(uint64_t));
|
|
||||||
if (target_conv.is_error())
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
m_last_read_ms = SystemTimer::get().ms_since_boot();
|
|
||||||
m_last_value = target_conv.value().as.integer.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto target_str = TRY(BAN::String::formatted("{}", m_last_value.load()));
|
|
||||||
|
|
||||||
if (static_cast<size_t>(offset) >= target_str.size())
|
if (static_cast<size_t>(offset) >= target_str.size())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const size_t ncopy = BAN::Math::min(buffer.size(), target_str.size() - offset);
|
const size_t ncopy = BAN::Math::min<size_t>(buffer.size(), target_str.size() - offset);
|
||||||
memcpy(buffer.data(), target_str.data() + offset, ncopy);
|
memcpy(buffer.data(), target_str.data() + offset, ncopy);
|
||||||
return ncopy;
|
return ncopy;
|
||||||
}
|
}
|
||||||
@@ -84,14 +62,44 @@ namespace Kernel::ACPI
|
|||||||
, m_result_index(index)
|
, m_result_index(index)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
BAN::ErrorOr<uint64_t> get_value()
|
||||||
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
|
if (SystemTimer::get().ms_since_boot() < m_last_read_ms + 1000)
|
||||||
|
return m_last_value;
|
||||||
|
|
||||||
|
auto [method_path, method_ref] = TRY(m_acpi_namespace.find_named_object(m_battery_path, m_method_name));
|
||||||
|
if (method_ref == nullptr)
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
|
||||||
|
auto result = TRY(AML::method_call(method_path, method_ref->node, BAN::Array<AML::Reference*, 7>{}));
|
||||||
|
if (result.type != AML::Node::Type::Package || result.as.package->num_elements < m_result_index)
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
|
||||||
|
auto& target_elem = result.as.package->elements[m_result_index];
|
||||||
|
if (!target_elem.resolved || !target_elem.value.node)
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
|
||||||
|
auto target_conv = AML::convert_node(TRY(target_elem.value.node->copy()), AML::ConvInteger, sizeof(uint64_t));
|
||||||
|
if (target_conv.is_error())
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
|
||||||
|
m_last_read_ms = SystemTimer::get().ms_since_boot();
|
||||||
|
m_last_value = target_conv.value().as.integer.value;
|
||||||
|
|
||||||
|
return m_last_value;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AML::Namespace& m_acpi_namespace;
|
AML::Namespace& m_acpi_namespace;
|
||||||
AML::Scope m_battery_path;
|
AML::Scope m_battery_path;
|
||||||
AML::NameString m_method_name;
|
AML::NameString m_method_name;
|
||||||
size_t m_result_index;
|
size_t m_result_index;
|
||||||
|
|
||||||
BAN::Atomic<uint64_t> m_last_read_ms = 0;
|
Mutex m_mutex;
|
||||||
BAN::Atomic<uint64_t> m_last_value = 0;
|
uint64_t m_last_read_ms = 0;
|
||||||
|
uint64_t m_last_value = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
BAN::ErrorOr<void> BatterySystem::initialize(AML::Namespace& acpi_namespace)
|
BAN::ErrorOr<void> BatterySystem::initialize(AML::Namespace& acpi_namespace)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <kernel/ACPI/EmbeddedController.h>
|
#include <kernel/ACPI/EmbeddedController.h>
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
#include <kernel/Lock/LockGuard.h>
|
#include <kernel/Lock/LockGuard.h>
|
||||||
|
#include <kernel/Scheduler.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
namespace Kernel::ACPI
|
namespace Kernel::ACPI
|
||||||
@@ -28,28 +30,18 @@ namespace Kernel::ACPI
|
|||||||
CMD_QUERY = 0x84,
|
CMD_QUERY = 0x84,
|
||||||
};
|
};
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<EmbeddedController>> EmbeddedController::create(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, BAN::Optional<uint8_t> gpe)
|
BAN::ErrorOr<BAN::UniqPtr<EmbeddedController>> EmbeddedController::create(AML::Scope&& scope, uint16_t command_port, uint16_t data_port)
|
||||||
{
|
{
|
||||||
auto* embedded_controller_ptr = new EmbeddedController(BAN::move(scope), command_port, data_port, gpe.has_value());
|
auto* embedded_controller_ptr = new EmbeddedController(BAN::move(scope), command_port, data_port);
|
||||||
if (embedded_controller_ptr == nullptr)
|
if (embedded_controller_ptr == nullptr)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
auto* thread = TRY(Thread::create_kernel([](void* ec) { static_cast<EmbeddedController*>(ec)->thread_task(); }, embedded_controller_ptr));
|
auto* thread = TRY(Thread::create_kernel([](void* ec) { static_cast<EmbeddedController*>(ec)->thread_task(); }, embedded_controller_ptr));
|
||||||
TRY(Processor::scheduler().add_thread(thread));
|
Processor::scheduler().add_thread(thread);
|
||||||
|
|
||||||
auto embedded_controller = BAN::UniqPtr<EmbeddedController>::adopt(embedded_controller_ptr);
|
auto embedded_controller = BAN::UniqPtr<EmbeddedController>::adopt(embedded_controller_ptr);
|
||||||
embedded_controller->m_thread = thread;
|
embedded_controller->m_thread = thread;
|
||||||
|
|
||||||
if (gpe.has_value())
|
|
||||||
TRY(ACPI::get().register_gpe_handler(gpe.value(), &handle_gpe_wrapper, embedded_controller.ptr()));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// FIXME: Restructure EC such that SCI_EVT can be polled.
|
|
||||||
// Simple solution would be spawning another thread,
|
|
||||||
// but that feels too hacky.
|
|
||||||
dwarnln("TODO: SCI_EVT polling without GPE");
|
|
||||||
}
|
|
||||||
|
|
||||||
return embedded_controller;
|
return embedded_controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,26 +85,25 @@ namespace Kernel::ACPI
|
|||||||
|
|
||||||
uint8_t EmbeddedController::read_one(uint16_t port)
|
uint8_t EmbeddedController::read_one(uint16_t port)
|
||||||
{
|
{
|
||||||
wait_status_bit(STS_OBF, 1);
|
wait_status_bit(STS_OBF, true);
|
||||||
return IO::inb(port);
|
return IO::inb(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmbeddedController::write_one(uint16_t port, uint8_t value)
|
void EmbeddedController::write_one(uint16_t port, uint8_t value)
|
||||||
{
|
{
|
||||||
wait_status_bit(STS_IBF, 0);
|
wait_status_bit(STS_IBF, false);
|
||||||
IO::outb(port, value);
|
IO::outb(port, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmbeddedController::wait_status_bit(uint8_t bit, uint8_t value)
|
void EmbeddedController::wait_status_bit(uint8_t mask, bool set)
|
||||||
{
|
{
|
||||||
// FIXME: timeouts
|
// FIXME: timeouts
|
||||||
const uint8_t mask = 1 << bit;
|
const uint8_t comp = set ? mask : 0;
|
||||||
const uint8_t comp = value ? mask : 0;
|
|
||||||
while ((IO::inb(m_command_port) & mask) != comp)
|
while ((IO::inb(m_command_port) & mask) != comp)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmbeddedController::handle_gpe_wrapper(void* embedded_controller)
|
void EmbeddedController::handle_gpe_trampoline(void* embedded_controller)
|
||||||
{
|
{
|
||||||
static_cast<EmbeddedController*>(embedded_controller)->handle_gpe();
|
static_cast<EmbeddedController*>(embedded_controller)->handle_gpe();
|
||||||
}
|
}
|
||||||
@@ -215,7 +206,7 @@ namespace Kernel::ACPI
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
Command* const command = m_queued_command.has_value() ? m_queued_command.value() : nullptr;
|
auto* const command = m_queued_command.value_or(nullptr);
|
||||||
m_queued_command.clear();
|
m_queued_command.clear();
|
||||||
|
|
||||||
if (command == nullptr)
|
if (command == nullptr)
|
||||||
@@ -224,27 +215,22 @@ namespace Kernel::ACPI
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use burst mode
|
||||||
|
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
|
|
||||||
if (command)
|
write_one(m_command_port, command->command);
|
||||||
{
|
if (command->data1.has_value())
|
||||||
// TODO: use burst mode
|
write_one(m_data_port, command->data1.value());
|
||||||
|
if (command->data2.has_value())
|
||||||
write_one(m_command_port, command->command);
|
write_one(m_data_port, command->data2.value());
|
||||||
if (command->data1.has_value())
|
if (command->response)
|
||||||
write_one(m_data_port, command->data1.value());
|
*command->response = read_one(m_data_port);
|
||||||
if (command->data2.has_value())
|
|
||||||
write_one(m_data_port, command->data2.value());
|
|
||||||
if (command->response)
|
|
||||||
*command->response = read_one(m_data_port);
|
|
||||||
|
|
||||||
m_mutex.lock();
|
|
||||||
command->done = true;
|
|
||||||
m_thread_blocker.unblock();
|
|
||||||
m_mutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
|
|
||||||
|
command->done = true;
|
||||||
|
m_thread_blocker.unblock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -351,17 +351,17 @@ namespace Kernel
|
|||||||
// give processor upto 100 * 100 us + 200 us to boot
|
// give processor upto 100 * 100 us + 200 us to boot
|
||||||
PageTable::with_fast_page(ap_init_paddr, [&] {
|
PageTable::with_fast_page(ap_init_paddr, [&] {
|
||||||
for (int i = 0; i < 100; i++, udelay(100))
|
for (int i = 0; i < 100; i++, udelay(100))
|
||||||
if (__atomic_load_n(&PageTable::fast_page_as<ap_init_info_t>(8).ready, __ATOMIC_SEQ_CST))
|
if (BAN::atomic_load(PageTable::fast_page_as<ap_init_info_t>(8).ready))
|
||||||
break;
|
break;
|
||||||
});
|
});
|
||||||
|
|
||||||
initialized_aps++;
|
initialized_aps++;
|
||||||
}
|
}
|
||||||
|
|
||||||
__atomic_store_n(&g_ap_startup_done[0], 1, __ATOMIC_SEQ_CST);
|
BAN::atomic_store(g_ap_startup_done[0], 1);
|
||||||
|
|
||||||
const size_t timeout_ms = SystemTimer::get().ms_since_boot() + 500;
|
const size_t timeout_ms = SystemTimer::get().ms_since_boot() + 500;
|
||||||
while (__atomic_load_n(&g_ap_running_count[0], __ATOMIC_SEQ_CST) < initialized_aps)
|
while (BAN::atomic_load(g_ap_running_count[0]) < initialized_aps)
|
||||||
{
|
{
|
||||||
if (SystemTimer::get().ms_since_boot() >= timeout_ms)
|
if (SystemTimer::get().ms_since_boot() >= timeout_ms)
|
||||||
Kernel::panic("Could not start all APs ({}/{} started)", g_ap_running_count[0], initialized_aps);
|
Kernel::panic("Could not start all APs ({}/{} started)", g_ap_running_count[0], initialized_aps);
|
||||||
@@ -511,9 +511,12 @@ namespace Kernel
|
|||||||
redir.lo_dword = ioapic->read(IOAPIC_REDIRS + pin * 2);
|
redir.lo_dword = ioapic->read(IOAPIC_REDIRS + pin * 2);
|
||||||
redir.hi_dword = ioapic->read(IOAPIC_REDIRS + pin * 2 + 1);
|
redir.hi_dword = ioapic->read(IOAPIC_REDIRS + pin * 2 + 1);
|
||||||
|
|
||||||
redir.trigger_mode = level_triggered;
|
|
||||||
redir.vector = IRQ_VECTOR_BASE + irq;
|
redir.vector = IRQ_VECTOR_BASE + irq;
|
||||||
|
redir.delivery_mode = 0; // fixed
|
||||||
|
redir.pin_polarity = 0; // active high
|
||||||
|
redir.trigger_mode = level_triggered;
|
||||||
redir.mask = 0;
|
redir.mask = 0;
|
||||||
|
redir.destination_mode = 0; // physical
|
||||||
// FIXME: distribute IRQs more evenly?
|
// FIXME: distribute IRQs more evenly?
|
||||||
redir.destination = Kernel::Processor::bsp_id().as_u32();
|
redir.destination = Kernel::Processor::bsp_id().as_u32();
|
||||||
|
|
||||||
|
|||||||
@@ -224,7 +224,12 @@ namespace Kernel
|
|||||||
BAN::ErrorOr<void> AC97AudioController::set_volume_mdB(int32_t mdB)
|
BAN::ErrorOr<void> AC97AudioController::set_volume_mdB(int32_t mdB)
|
||||||
{
|
{
|
||||||
m_volume_info.mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
|
m_volume_info.mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
|
||||||
m_mixer->write16(AudioMixerRegister::MasterVolume, get_volume_data());
|
|
||||||
|
const uint32_t volume_data = get_volume_data();
|
||||||
|
m_mixer->write16(AudioMixerRegister::MasterVolume, volume_data);
|
||||||
|
|
||||||
|
m_volume_info.mdB = -(volume_data & 0xFF) * m_volume_info.step_mdB;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <kernel/Device/DeviceNumbers.h>
|
#include <kernel/Device/DeviceNumbers.h>
|
||||||
#include <kernel/FS/DevFS/FileSystem.h>
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
#include <kernel/Lock/BlockableSpinLock.h>
|
#include <kernel/Lock/BlockableSpinLock.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
|
|||||||
@@ -139,31 +139,27 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::ErrorOr<void> HDAudioFunctionGroup::set_volume_mdB(int32_t mdB)
|
BAN::ErrorOr<void> HDAudioFunctionGroup::set_volume_mdB(int32_t mdB)
|
||||||
{
|
{
|
||||||
|
if (m_amplifier_idx == SIZE_MAX)
|
||||||
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
|
||||||
mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
|
mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
|
||||||
|
|
||||||
const auto& path = m_output_paths[m_output_path_index];
|
const auto* node = m_output_paths[m_output_path_index][m_amplifier_idx];
|
||||||
for (size_t i = 0; i < path.size(); i++)
|
|
||||||
{
|
|
||||||
if (!path[i]->output_amplifier.has_value())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const int32_t step_round = (mdB >= 0)
|
const int32_t step_round = (mdB >= 0)
|
||||||
? +m_volume_info.step_mdB / 2
|
? +m_volume_info.step_mdB / 2
|
||||||
: -m_volume_info.step_mdB / 2;
|
: -m_volume_info.step_mdB / 2;
|
||||||
const uint32_t step = (mdB + step_round) / m_volume_info.step_mdB + path[i]->output_amplifier->offset;
|
const uint32_t step = (mdB + step_round) / m_volume_info.step_mdB + node->output_amplifier->offset;
|
||||||
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | step;
|
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | step;
|
||||||
|
|
||||||
TRY(m_controller->send_command({
|
TRY(m_controller->send_command({
|
||||||
.data = static_cast<uint8_t>(volume & 0xFF),
|
.data = static_cast<uint8_t>(volume & 0xFF),
|
||||||
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
||||||
.node_index = path[i]->id,
|
.node_index = node->id,
|
||||||
.codec_address = m_cid,
|
.codec_address = m_cid,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
break;
|
m_volume_info.mdB = (mdB + step_round) / m_volume_info.step_mdB * m_volume_info.step_mdB;
|
||||||
}
|
|
||||||
|
|
||||||
m_volume_info.mdB = mdB;
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -331,8 +327,8 @@ namespace Kernel
|
|||||||
uint16_t HDAudioFunctionGroup::get_format_data() const
|
uint16_t HDAudioFunctionGroup::get_format_data() const
|
||||||
{
|
{
|
||||||
// TODO: don't hardcode this
|
// TODO: don't hardcode this
|
||||||
// format: PCM, 48 kHz, 16 bit, 2 channels
|
// format: PCM, 48 kHz, 16 bit
|
||||||
return 0b0'0'000'000'0'001'0001;
|
return 0b0'0'000'000'0'001'0000 | (get_channels() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index)
|
BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index)
|
||||||
@@ -346,6 +342,8 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
using HDAudio::AFGWidget;
|
using HDAudio::AFGWidget;
|
||||||
case AFGWidget::Type::OutputConverter:
|
case AFGWidget::Type::OutputConverter:
|
||||||
|
case AFGWidget::Type::Mixer:
|
||||||
|
case AFGWidget::Type::Selector:
|
||||||
case AFGWidget::Type::PinComplex:
|
case AFGWidget::Type::PinComplex:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -367,7 +365,7 @@ namespace Kernel
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// set connection index
|
// set connection index
|
||||||
if (i + 1 < path.size() && path[i]->connections.size() > 1)
|
if (i + 1 < path.size() && path[i]->connections.size() > 1 && path[i]->type != HDAudio::AFGWidget::Type::Mixer)
|
||||||
{
|
{
|
||||||
uint8_t index = 0;
|
uint8_t index = 0;
|
||||||
for (; index < path[i]->connections.size(); index++)
|
for (; index < path[i]->connections.size(); index++)
|
||||||
@@ -407,6 +405,13 @@ namespace Kernel
|
|||||||
.node_index = path[i]->id,
|
.node_index = path[i]->id,
|
||||||
.codec_address = m_cid,
|
.codec_address = m_cid,
|
||||||
}));
|
}));
|
||||||
|
// set channel count
|
||||||
|
TRY(m_controller->send_command({
|
||||||
|
.data = static_cast<uint8_t>(get_channels() - 1),
|
||||||
|
.command = 0x72D,
|
||||||
|
.node_index = path[i]->id,
|
||||||
|
.codec_address = m_cid,
|
||||||
|
}));
|
||||||
// set format
|
// set format
|
||||||
TRY(m_controller->send_command({
|
TRY(m_controller->send_command({
|
||||||
.data = static_cast<uint8_t>(format & 0xFF),
|
.data = static_cast<uint8_t>(format & 0xFF),
|
||||||
@@ -416,6 +421,28 @@ namespace Kernel
|
|||||||
}));
|
}));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AFGWidget::Type::Mixer:
|
||||||
|
if (path[i]->input_amplifier.has_value())
|
||||||
|
{
|
||||||
|
for (size_t idx = 0; idx < path[i]->connections.size(); idx++)
|
||||||
|
{
|
||||||
|
const uint8_t step = (path[i]->connections[idx] == path[i + 1]->id)
|
||||||
|
? path[i]->input_amplifier->offset
|
||||||
|
: 0b1'0000000;
|
||||||
|
const uint32_t volume = 0b0'1'1'1'0000'0'0000000 | (idx << 8) | step;
|
||||||
|
TRY(m_controller->send_command({
|
||||||
|
.data = static_cast<uint8_t>(volume & 0xFF),
|
||||||
|
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
||||||
|
.node_index = path[i]->id,
|
||||||
|
.codec_address = m_cid,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AFGWidget::Type::Selector:
|
||||||
|
break;
|
||||||
|
|
||||||
case AFGWidget::Type::PinComplex:
|
case AFGWidget::Type::PinComplex:
|
||||||
// enable output and H-Phn
|
// enable output and H-Phn
|
||||||
TRY(m_controller->send_command({
|
TRY(m_controller->send_command({
|
||||||
@@ -438,15 +465,25 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update volume info to this path
|
int32_t max_steps { 0 };
|
||||||
m_volume_info.min_mdB = 0;
|
m_amplifier_idx = SIZE_MAX;
|
||||||
m_volume_info.max_mdB = 0;
|
|
||||||
m_volume_info.step_mdB = 0;
|
|
||||||
for (size_t i = 0; i < path.size(); i++)
|
for (size_t i = 0; i < path.size(); i++)
|
||||||
{
|
{
|
||||||
if (!path[i]->output_amplifier.has_value())
|
if (!path[i]->output_amplifier.has_value())
|
||||||
continue;
|
continue;
|
||||||
const auto& amp = path[i]->output_amplifier.value();
|
if (auto steps = path[i]->output_amplifier->num_steps; steps > max_steps)
|
||||||
|
{
|
||||||
|
max_steps = steps;
|
||||||
|
m_amplifier_idx = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_amplifier_idx == SIZE_MAX)
|
||||||
|
m_volume_info = {};
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto& amp = path[m_amplifier_idx]->output_amplifier.value();
|
||||||
|
|
||||||
const int32_t step_mdB = (amp.step_size + 1) * 250;
|
const int32_t step_mdB = (amp.step_size + 1) * 250;
|
||||||
m_volume_info.step_mdB = step_mdB;
|
m_volume_info.step_mdB = step_mdB;
|
||||||
@@ -463,16 +500,11 @@ namespace Kernel
|
|||||||
TRY(m_controller->send_command({
|
TRY(m_controller->send_command({
|
||||||
.data = static_cast<uint8_t>(volume & 0xFF),
|
.data = static_cast<uint8_t>(volume & 0xFF),
|
||||||
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
||||||
.node_index = path[i]->id,
|
.node_index = path[m_amplifier_idx]->id,
|
||||||
.codec_address = m_cid,
|
.codec_address = m_cid,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_volume_info.min_mdB == 0 && m_volume_info.max_mdB == 0)
|
|
||||||
m_volume_info.mdB = 0;
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,6 +528,8 @@ namespace Kernel
|
|||||||
using HDAudio::AFGWidget;
|
using HDAudio::AFGWidget;
|
||||||
|
|
||||||
case AFGWidget::Type::OutputConverter:
|
case AFGWidget::Type::OutputConverter:
|
||||||
|
case AFGWidget::Type::Mixer:
|
||||||
|
case AFGWidget::Type::Selector:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AFGWidget::Type::PinComplex:
|
case AFGWidget::Type::PinComplex:
|
||||||
@@ -635,11 +669,8 @@ namespace Kernel
|
|||||||
m_bdl_tail = (m_bdl_tail + 1) % m_bdl_entry_count;
|
m_bdl_tail = (m_bdl_tail + 1) % m_bdl_entry_count;
|
||||||
if (m_bdl_tail == m_bdl_head)
|
if (m_bdl_tail == m_bdl_head)
|
||||||
{
|
{
|
||||||
if (auto ret = reset_stream(); ret.is_error())
|
bar.write8(base + Regs::SDCTL, bar.read8(base + Regs::SDCTL) & 0xFD);
|
||||||
{
|
m_stream_running = false;
|
||||||
dwarnln("failed to reset HDA stream: {}", ret.error());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_bdl_data();
|
queue_bdl_data();
|
||||||
|
|||||||
@@ -333,6 +333,20 @@ namespace Kernel
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (const uint32_t in_amp_cap = send_command_or_zero(0xF00, 0x0D))
|
||||||
|
{
|
||||||
|
const uint8_t offset = (in_amp_cap >> 0) & 0x7F;
|
||||||
|
const uint8_t num_steps = (in_amp_cap >> 8) & 0x7F;
|
||||||
|
const uint8_t step_size = (in_amp_cap >> 16) & 0x7F;
|
||||||
|
const bool mute = (in_amp_cap >> 31);
|
||||||
|
result.input_amplifier = HDAudio::AFGWidget::Amplifier {
|
||||||
|
.offset = offset,
|
||||||
|
.num_steps = num_steps,
|
||||||
|
.step_size = step_size,
|
||||||
|
.mute = mute,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const uint8_t connection_info = send_command_or_zero(0xF00, 0x0E);
|
const uint8_t connection_info = send_command_or_zero(0xF00, 0x0E);
|
||||||
const uint8_t conn_width = (connection_info & 0x80) ? 2 : 1;
|
const uint8_t conn_width = (connection_info & 0x80) ? 2 : 1;
|
||||||
const uint8_t conn_count = connection_info & 0x3F;
|
const uint8_t conn_count = connection_info & 0x3F;
|
||||||
|
|||||||
+14
-1
@@ -14,6 +14,8 @@
|
|||||||
#include <kernel/Lock/SpinLock.h>
|
#include <kernel/Lock/SpinLock.h>
|
||||||
#include <kernel/UserCopy.h>
|
#include <kernel/UserCopy.h>
|
||||||
|
|
||||||
|
#if ARCH(x86_64)
|
||||||
|
|
||||||
using namespace LibELF;
|
using namespace LibELF;
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
@@ -204,7 +206,7 @@ BAN::ErrorOr<size_t> Banos::load_driver_from_image(const char* u_image) {
|
|||||||
// NOTE: should be more than plenty ;)
|
// NOTE: should be more than plenty ;)
|
||||||
extern char g_drv_builtin_begin[];
|
extern char g_drv_builtin_begin[];
|
||||||
extern char g_drv_builtin_end[];
|
extern char g_drv_builtin_end[];
|
||||||
void Banos::initialize_initial_drivers(void) {
|
void Banos::initialize_initial_drivers() {
|
||||||
import_symbols(g_banos_export, g_banos_export_end - g_banos_export);
|
import_symbols(g_banos_export, g_banos_export_end - g_banos_export);
|
||||||
char* head = g_drv_builtin_begin;
|
char* head = g_drv_builtin_begin;
|
||||||
while(head < g_drv_builtin_end) {
|
while(head < g_drv_builtin_end) {
|
||||||
@@ -213,3 +215,14 @@ void Banos::initialize_initial_drivers(void) {
|
|||||||
head += drv->driver_size;
|
head += drv->driver_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
void Banos::initialize_initial_drivers()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
BAN::ErrorOr<size_t> Banos::load_driver_from_image(const char* u_image)
|
||||||
|
{
|
||||||
|
(void)u_image;
|
||||||
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <kernel/Device/DeviceNumbers.h>
|
#include <kernel/Device/DeviceNumbers.h>
|
||||||
#include <kernel/Device/FramebufferDevice.h>
|
#include <kernel/Device/FramebufferDevice.h>
|
||||||
#include <kernel/FS/DevFS/FileSystem.h>
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
|
#include <kernel/Graphics/BGA.h>
|
||||||
#include <kernel/Memory/Heap.h>
|
#include <kernel/Memory/Heap.h>
|
||||||
#include <kernel/Terminal/FramebufferTerminal.h>
|
#include <kernel/Terminal/FramebufferTerminal.h>
|
||||||
|
|
||||||
@@ -26,19 +27,14 @@ namespace Kernel
|
|||||||
return s_boot_framebuffer;
|
return s_boot_framebuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> FramebufferDevice::create_from_boot_framebuffer()
|
BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> FramebufferDevice::create(paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch, uint8_t bpp)
|
||||||
{
|
{
|
||||||
ASSERT(g_boot_info.framebuffer.type == FramebufferInfo::Type::RGB);
|
if (bpp != 24 && bpp != 32)
|
||||||
if (g_boot_info.framebuffer.bpp != 24 && g_boot_info.framebuffer.bpp != 32)
|
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
auto* device_ptr = new FramebufferDevice(
|
auto* device_ptr = new FramebufferDevice(
|
||||||
0660, 0, 900,
|
0660, 0, 900,
|
||||||
makedev(DeviceNumber::Framebuffer, get_framebuffer_device_index()),
|
makedev(DeviceNumber::Framebuffer, get_framebuffer_device_index()),
|
||||||
g_boot_info.framebuffer.address,
|
paddr, width, height, pitch, bpp
|
||||||
g_boot_info.framebuffer.width,
|
|
||||||
g_boot_info.framebuffer.height,
|
|
||||||
g_boot_info.framebuffer.pitch,
|
|
||||||
g_boot_info.framebuffer.bpp
|
|
||||||
);
|
);
|
||||||
if (device_ptr == nullptr)
|
if (device_ptr == nullptr)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
@@ -49,6 +45,33 @@ namespace Kernel
|
|||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> FramebufferDevice::create(BAN::RefPtr<BGAController> bga_controller)
|
||||||
|
{
|
||||||
|
const auto fix_info = bga_controller->get_fb_fix_info();
|
||||||
|
const auto var_info = bga_controller->get_fb_var_info();
|
||||||
|
auto controller = TRY(create(
|
||||||
|
fix_info.mem_start,
|
||||||
|
var_info.xres,
|
||||||
|
var_info.yres,
|
||||||
|
fix_info.pitch,
|
||||||
|
var_info.bpp
|
||||||
|
));
|
||||||
|
controller->m_bga_controller = bga_controller;
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> FramebufferDevice::create_from_boot_framebuffer()
|
||||||
|
{
|
||||||
|
s_boot_framebuffer = TRY(create(
|
||||||
|
g_boot_info.framebuffer.address,
|
||||||
|
g_boot_info.framebuffer.width,
|
||||||
|
g_boot_info.framebuffer.height,
|
||||||
|
g_boot_info.framebuffer.pitch,
|
||||||
|
g_boot_info.framebuffer.bpp
|
||||||
|
));
|
||||||
|
return s_boot_framebuffer;
|
||||||
|
}
|
||||||
|
|
||||||
FramebufferDevice::FramebufferDevice(mode_t mode, uid_t uid, gid_t gid, dev_t rdev, paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch, uint8_t bpp)
|
FramebufferDevice::FramebufferDevice(mode_t mode, uid_t uid, gid_t gid, dev_t rdev, paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch, uint8_t bpp)
|
||||||
: CharacterDevice(mode, uid, gid)
|
: CharacterDevice(mode, uid, gid)
|
||||||
, m_name(MUST(BAN::String::formatted("fb{}", minor(rdev))))
|
, m_name(MUST(BAN::String::formatted("fb{}", minor(rdev))))
|
||||||
@@ -65,16 +88,20 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
if (m_video_memory_vaddr == 0)
|
if (m_video_memory_vaddr == 0)
|
||||||
return;
|
return;
|
||||||
size_t video_memory_pages = range_page_count(m_video_memory_paddr, m_height * m_pitch);
|
const size_t video_memory_bytes = m_bga_controller ? m_bga_controller->get_fb_fix_info().mem_size : m_height * m_pitch;
|
||||||
|
const size_t video_memory_pages = range_page_count(m_video_memory_paddr, video_memory_bytes);
|
||||||
PageTable::kernel().unmap_range(m_video_memory_vaddr, video_memory_pages * PAGE_SIZE);
|
PageTable::kernel().unmap_range(m_video_memory_vaddr, video_memory_pages * PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> FramebufferDevice::initialize()
|
BAN::ErrorOr<void> FramebufferDevice::initialize()
|
||||||
{
|
{
|
||||||
size_t video_memory_pages = range_page_count(m_video_memory_paddr, m_height * m_pitch);
|
const size_t video_memory_bytes = m_bga_controller ? m_bga_controller->get_fb_fix_info().mem_size : m_height * m_pitch;
|
||||||
|
const size_t video_memory_pages = range_page_count(m_video_memory_paddr, video_memory_bytes);
|
||||||
|
|
||||||
m_video_memory_vaddr = PageTable::kernel().reserve_free_contiguous_pages(video_memory_pages, KERNEL_OFFSET);
|
m_video_memory_vaddr = PageTable::kernel().reserve_free_contiguous_pages(video_memory_pages, KERNEL_OFFSET);
|
||||||
if (m_video_memory_vaddr == 0)
|
if (m_video_memory_vaddr == 0)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
PageTable::kernel().map_range_at(
|
PageTable::kernel().map_range_at(
|
||||||
m_video_memory_paddr & PAGE_ADDR_MASK,
|
m_video_memory_paddr & PAGE_ADDR_MASK,
|
||||||
m_video_memory_vaddr,
|
m_video_memory_vaddr,
|
||||||
@@ -86,7 +113,7 @@ namespace Kernel
|
|||||||
m_video_buffer = TRY(VirtualRange::create_to_vaddr_range(
|
m_video_buffer = TRY(VirtualRange::create_to_vaddr_range(
|
||||||
PageTable::kernel(),
|
PageTable::kernel(),
|
||||||
{ KERNEL_OFFSET, UINTPTR_MAX },
|
{ KERNEL_OFFSET, UINTPTR_MAX },
|
||||||
BAN::Math::div_round_up<size_t>(m_width * m_height * (BANAN_FB_BPP / 8), PAGE_SIZE) * PAGE_SIZE,
|
video_memory_pages * PAGE_SIZE,
|
||||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||||
false
|
false
|
||||||
));
|
));
|
||||||
@@ -94,6 +121,37 @@ namespace Kernel
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> FramebufferDevice::set_bga_controller(BAN::RefPtr<BGAController> bga_controller)
|
||||||
|
{
|
||||||
|
ASSERT(!m_bga_controller);
|
||||||
|
|
||||||
|
if (auto var_info = bga_controller->get_fb_var_info(); var_info.bpp != 32)
|
||||||
|
{
|
||||||
|
var_info.bpp = 32;
|
||||||
|
TRY(bga_controller->set_fb_var_info(var_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto fix_info = bga_controller->get_fb_fix_info();
|
||||||
|
const auto var_info = bga_controller->get_fb_var_info();
|
||||||
|
|
||||||
|
ASSERT(m_video_memory_vaddr);
|
||||||
|
PageTable::kernel().unmap_range(m_video_memory_vaddr, m_height * m_pitch);
|
||||||
|
|
||||||
|
m_video_memory_vaddr = 0;
|
||||||
|
m_video_memory_paddr = fix_info.mem_start;
|
||||||
|
|
||||||
|
m_width = var_info.xres;
|
||||||
|
m_height = var_info.yres;
|
||||||
|
m_pitch = fix_info.pitch;
|
||||||
|
m_bpp = var_info.bpp;
|
||||||
|
|
||||||
|
m_bga_controller = bga_controller;
|
||||||
|
|
||||||
|
TRY(initialize());
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> FramebufferDevice::read_impl(off_t offset, BAN::ByteSpan buffer)
|
BAN::ErrorOr<size_t> FramebufferDevice::read_impl(off_t offset, BAN::ByteSpan buffer)
|
||||||
{
|
{
|
||||||
// Reading from negative offset will fill buffer with framebuffer info
|
// Reading from negative offset will fill buffer with framebuffer info
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <kernel/Epoll.h>
|
#include <kernel/Epoll.h>
|
||||||
#include <kernel/Lock/BlockableSpinLock.h>
|
#include <kernel/Lock/BlockableSpinLock.h>
|
||||||
#include <kernel/Lock/LockGuard.h>
|
#include <kernel/Lock/LockGuard.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}, s_instance
|
}, s_instance
|
||||||
));
|
));
|
||||||
MUST(Processor::scheduler().add_thread(updater_thread));
|
Processor::scheduler().add_thread(updater_thread);
|
||||||
|
|
||||||
auto* disk_cache_drop_thread = MUST(Thread::create_kernel(
|
auto* disk_cache_drop_thread = MUST(Thread::create_kernel(
|
||||||
[](void* _devfs)
|
[](void* _devfs)
|
||||||
@@ -93,7 +93,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}, s_instance
|
}, s_instance
|
||||||
));
|
));
|
||||||
MUST(Processor::scheduler().add_thread(disk_cache_drop_thread));
|
Processor::scheduler().add_thread(disk_cache_drop_thread);
|
||||||
|
|
||||||
auto* disk_sync_thread = MUST(Thread::create_kernel(
|
auto* disk_sync_thread = MUST(Thread::create_kernel(
|
||||||
[](void* _devfs)
|
[](void* _devfs)
|
||||||
@@ -129,7 +129,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}, s_instance
|
}, s_instance
|
||||||
));
|
));
|
||||||
MUST(Processor::scheduler().add_thread(disk_sync_thread));
|
Processor::scheduler().add_thread(disk_sync_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevFileSystem::initiate_disk_cache_drop()
|
void DevFileSystem::initiate_disk_cache_drop()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <kernel/FS/EventFD.h>
|
#include <kernel/FS/EventFD.h>
|
||||||
#include <kernel/Lock/LockGuard.h>
|
#include <kernel/Lock/LockGuard.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
|
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ namespace Kernel
|
|||||||
while (m_value == 0)
|
while (m_value == 0)
|
||||||
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
|
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
|
||||||
|
|
||||||
const uint64_t read_value = m_is_semaphore ? 1 : m_value.load();
|
const uint64_t read_value = m_is_semaphore ? 1 : m_value;
|
||||||
m_value -= read_value;
|
m_value -= read_value;
|
||||||
|
|
||||||
buffer.as<uint64_t>() = read_value;
|
buffer.as<uint64_t>() = read_value;
|
||||||
@@ -79,4 +80,16 @@ namespace Kernel
|
|||||||
return sizeof(uint64_t);
|
return sizeof(uint64_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EventFD::can_read_impl() const
|
||||||
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
return m_value > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EventFD::can_write_impl() const
|
||||||
|
{
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
return m_value < UINT64_MAX - 1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <BAN/Sort.h>
|
#include <BAN/Sort.h>
|
||||||
#include <kernel/FS/Ext2/FileSystem.h>
|
#include <kernel/FS/Ext2/FileSystem.h>
|
||||||
#include <kernel/Lock/LockGuard.h>
|
#include <kernel/Lock/LockGuard.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
|
|
||||||
#define EXT2_DEBUG_PRINT 0
|
#define EXT2_DEBUG_PRINT 0
|
||||||
#define EXT2_VERIFY_INODE 0
|
#define EXT2_VERIFY_INODE 0
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <kernel/Device/Device.h>
|
||||||
#include <kernel/FS/FAT/FileSystem.h>
|
#include <kernel/FS/FAT/FileSystem.h>
|
||||||
#include <kernel/Lock/LockGuard.h>
|
#include <kernel/Lock/LockGuard.h>
|
||||||
|
|
||||||
@@ -123,18 +124,6 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
uint32_t block_count = 0;
|
|
||||||
{
|
|
||||||
uint32_t cluster = entry.first_cluster_lo;
|
|
||||||
if (m_type == Type::FAT32)
|
|
||||||
cluster |= static_cast<uint32_t>(entry.first_cluster_hi) << 16;
|
|
||||||
while (cluster >= 2 && cluster < cluster_count())
|
|
||||||
{
|
|
||||||
block_count++;
|
|
||||||
cluster = TRY(get_next_cluster(cluster));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t entry_cluster;
|
uint32_t entry_cluster;
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
@@ -143,25 +132,34 @@ namespace Kernel
|
|||||||
if (parent == m_root_inode)
|
if (parent == m_root_inode)
|
||||||
entry_cluster = 1;
|
entry_cluster = 1;
|
||||||
else
|
else
|
||||||
{
|
|
||||||
entry_cluster = parent->entry().first_cluster_lo;
|
entry_cluster = parent->entry().first_cluster_lo;
|
||||||
for (uint32_t i = 0; i < cluster_index; i++)
|
|
||||||
entry_cluster = TRY(get_next_cluster(entry_cluster));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Type::FAT32:
|
case Type::FAT32:
|
||||||
if (parent == m_root_inode)
|
if (parent == m_root_inode)
|
||||||
entry_cluster = m_bpb.ext_32.root_cluster;
|
entry_cluster = m_bpb.ext_32.root_cluster;
|
||||||
else
|
else
|
||||||
entry_cluster = (static_cast<uint32_t>(parent->entry().first_cluster_hi) << 16) | parent->entry().first_cluster_lo;
|
entry_cluster = (static_cast<uint32_t>(parent->entry().first_cluster_hi) << 16) | parent->entry().first_cluster_lo;
|
||||||
for (uint32_t i = 0; i < cluster_index; i++)
|
|
||||||
entry_cluster = TRY(get_next_cluster(entry_cluster));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ino_t ino = (static_cast<ino_t>(entry_cluster) << 32) | entry_index;
|
uint32_t block_count = 0;
|
||||||
|
for (uint32_t i = 0; i < cluster_index; i++)
|
||||||
|
{
|
||||||
|
block_count++;
|
||||||
|
entry_cluster = TRY(get_next_cluster(entry_cluster));
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t dirent_per_cluster = m_bpb.bytes_per_sector * m_bpb.sectors_per_cluster / sizeof(FAT::DirectoryEntry);
|
||||||
|
ASSERT(BAN::Math::is_power_of_two(dirent_per_cluster));
|
||||||
|
ASSERT(entry_index < dirent_per_cluster);
|
||||||
|
|
||||||
|
const uint32_t ino_cluster_shift = BAN::Math::ctz(dirent_per_cluster);
|
||||||
|
const ino_t ino = (static_cast<ino_t>(entry_cluster) << ino_cluster_shift) | entry_index;
|
||||||
|
if (ino >> ino_cluster_shift != entry_cluster)
|
||||||
|
dwarnln("FAT ino mapping not unique");
|
||||||
|
|
||||||
auto it = m_inode_cache.find(ino);
|
auto it = m_inode_cache.find(ino);
|
||||||
if (it != m_inode_cache.end())
|
if (it != m_inode_cache.end())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <BAN/Time.h>
|
#include <BAN/Time.h>
|
||||||
|
|
||||||
|
#include <kernel/Device/Device.h>
|
||||||
#include <kernel/FS/FAT/FileSystem.h>
|
#include <kernel/FS/FAT/FileSystem.h>
|
||||||
#include <kernel/FS/FAT/Inode.h>
|
#include <kernel/FS/FAT/Inode.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <kernel/BootInfo.h>
|
#include <kernel/BootInfo.h>
|
||||||
#include <kernel/FS/ProcFS/FileSystem.h>
|
#include <kernel/FS/ProcFS/FileSystem.h>
|
||||||
#include <kernel/FS/ProcFS/Inode.h>
|
#include <kernel/FS/ProcFS/Inode.h>
|
||||||
|
#include <kernel/Process.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <kernel/FS/ProcFS/Inode.h>
|
#include <kernel/FS/ProcFS/Inode.h>
|
||||||
|
#include <kernel/Process.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,242 @@
|
|||||||
|
#include <kernel/Device/FramebufferDevice.h>
|
||||||
|
#include <kernel/Graphics/BGA.h>
|
||||||
|
#include <kernel/IO.h>
|
||||||
|
#include <kernel/Terminal/FramebufferTerminal.h>
|
||||||
|
#include <kernel/Terminal/VirtualTTY.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
enum BGA_IO_PORT : uint16_t
|
||||||
|
{
|
||||||
|
BGA_IO_PORT_INDEX = 0x1CE,
|
||||||
|
BGA_IO_PORT_DATA = 0x1CF,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BGA_REG : uint16_t
|
||||||
|
{
|
||||||
|
BGA_REG_ID = 0,
|
||||||
|
BGA_REG_XRES = 1,
|
||||||
|
BGA_REG_YRES = 2,
|
||||||
|
BGA_REG_BPP = 3,
|
||||||
|
BGA_REG_ENABLE = 4,
|
||||||
|
BGA_REG_BANK = 5,
|
||||||
|
BGA_REG_XRES_VIRT = 6,
|
||||||
|
BGA_REG_YRES_VIRT = 7,
|
||||||
|
BGA_REG_XOFF = 8,
|
||||||
|
BGA_REG_YOFF = 9,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BGA_ID : uint16_t
|
||||||
|
{
|
||||||
|
BGA_ID_0 = 0xB0C0,
|
||||||
|
BGA_ID_1 = 0xB0C1,
|
||||||
|
BGA_ID_2 = 0xB0C2,
|
||||||
|
BGA_ID_3 = 0xB0C3,
|
||||||
|
BGA_ID_4 = 0xB0C4,
|
||||||
|
BGA_ID_5 = 0xB0C5,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BGA_ENABLE : uint16_t
|
||||||
|
{
|
||||||
|
BGA_ENABLE_ENABLE = 0x01,
|
||||||
|
BGA_ENABLE_LFB_ENABLE = 0x40,
|
||||||
|
BGA_ENABLE_NOCLEARMEM = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::RefPtr<BGAController>> BGAController::create(PCI::Device& pci_device)
|
||||||
|
{
|
||||||
|
auto* bga_controller_ptr = new BGAController(pci_device);
|
||||||
|
if (bga_controller_ptr == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
auto bga_controller = BAN::RefPtr<BGAController>::adopt(bga_controller_ptr);
|
||||||
|
TRY(bga_controller->initialize());
|
||||||
|
return bga_controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
BGAController::BGAController(PCI::Device& pci_device)
|
||||||
|
: m_pci_device(pci_device)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> BGAController::initialize()
|
||||||
|
{
|
||||||
|
auto boot_framebuffer = FramebufferDevice::boot_framebuffer();
|
||||||
|
|
||||||
|
m_lfb_bar = TRY(m_pci_device.allocate_bar_region(0));
|
||||||
|
if (m_lfb_bar->type() != PCI::BarType::MEM)
|
||||||
|
{
|
||||||
|
dwarnln("BGA LFB is not memory bar");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fix_info = {
|
||||||
|
.xpanstep = 1,
|
||||||
|
.ypanstep = 1,
|
||||||
|
.pitch = 0,
|
||||||
|
.mem_start = static_cast<uint64_t>(m_lfb_bar->paddr()),
|
||||||
|
.mem_size = static_cast<uint32_t>(m_lfb_bar->size()),
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto ready_to_use_flags = BGA_ENABLE_LFB_ENABLE | BGA_ENABLE_ENABLE;
|
||||||
|
if ((read_reg(BGA_REG_ENABLE) & ready_to_use_flags) == ready_to_use_flags)
|
||||||
|
{
|
||||||
|
m_var_info = {
|
||||||
|
.xres = read_reg(BGA_REG_XRES),
|
||||||
|
.yres = read_reg(BGA_REG_YRES),
|
||||||
|
.xres_virt = read_reg(BGA_REG_XRES_VIRT),
|
||||||
|
.yres_virt = read_reg(BGA_REG_XRES_VIRT),
|
||||||
|
.xoff = read_reg(BGA_REG_XOFF),
|
||||||
|
.yoff = read_reg(BGA_REG_YOFF),
|
||||||
|
.bpp = read_reg(BGA_REG_BPP),
|
||||||
|
};
|
||||||
|
|
||||||
|
m_fix_info.pitch = m_var_info.xres_virt * m_var_info.bpp / 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const uint32_t xres = boot_framebuffer ? boot_framebuffer->width() : 1280;
|
||||||
|
const uint32_t yres = boot_framebuffer ? boot_framebuffer->height() : 800;
|
||||||
|
const uint32_t bpp = boot_framebuffer ? boot_framebuffer->bpp() : 32;
|
||||||
|
|
||||||
|
TRY(set_fb_var_info({
|
||||||
|
.xres = xres,
|
||||||
|
.yres = yres,
|
||||||
|
.xres_virt = xres,
|
||||||
|
.yres_virt = yres * 2,
|
||||||
|
.xoff = 0,
|
||||||
|
.yoff = 0,
|
||||||
|
.bpp = bpp,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boot_framebuffer)
|
||||||
|
{
|
||||||
|
// FIXME: check that this is actually the boot framebuffer
|
||||||
|
TRY(boot_framebuffer->set_bga_controller(this));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto framebuffer_device = TRY(FramebufferDevice::create(this));
|
||||||
|
auto fb_terminal_driver = TRY(FramebufferTerminalDriver::create(framebuffer_device));
|
||||||
|
|
||||||
|
// FIXME: query vtty instead of checking the current tty
|
||||||
|
if (auto tty = TTY::current(); tty && tty->is_vtty())
|
||||||
|
TRY(static_cast<VirtualTTY*>(tty.ptr())->set_terminal_driver(fb_terminal_driver));
|
||||||
|
else
|
||||||
|
TRY(VirtualTTY::create(fb_terminal_driver));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> BGAController::set_fb_var_info(const fb_var_info& var_info)
|
||||||
|
{
|
||||||
|
const auto validate_u16 = [](auto value) -> BAN::ErrorOr<void> {
|
||||||
|
if (value > BAN::numeric_limits<uint16_t>::max())
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
TRY(validate_u16(var_info.xres));
|
||||||
|
TRY(validate_u16(var_info.xres));
|
||||||
|
TRY(validate_u16(var_info.xres_virt));
|
||||||
|
TRY(validate_u16(var_info.yres_virt));
|
||||||
|
TRY(validate_u16(var_info.xoff));
|
||||||
|
TRY(validate_u16(var_info.yoff));
|
||||||
|
TRY(validate_u16(var_info.bpp));
|
||||||
|
|
||||||
|
if (var_info.xres + var_info.xoff > var_info.xres_virt)
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
if (var_info.yres + var_info.yoff > var_info.yres_virt)
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
if (static_cast<uint64_t>(var_info.xres_virt) * var_info.yres_virt * var_info.bpp / 8 > m_lfb_bar->size())
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
const bool needs_reconf =
|
||||||
|
(m_var_info.xres != var_info.xres) ||
|
||||||
|
(m_var_info.yres != var_info.yres) ||
|
||||||
|
(m_var_info.xres_virt != var_info.xres_virt) ||
|
||||||
|
(m_var_info.yres_virt != var_info.yres_virt) ||
|
||||||
|
(m_var_info.bpp != var_info.bpp);
|
||||||
|
|
||||||
|
if (!needs_reconf)
|
||||||
|
{
|
||||||
|
write_reg(BGA_REG_XOFF, var_info.xoff);
|
||||||
|
write_reg(BGA_REG_YOFF, var_info.yoff);
|
||||||
|
m_var_info.xoff = var_info.xoff;
|
||||||
|
m_var_info.yoff = var_info.yoff;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto old_enable = read_reg(BGA_REG_ENABLE);
|
||||||
|
write_reg(BGA_REG_ENABLE, 0);
|
||||||
|
|
||||||
|
write_reg(BGA_REG_BPP, var_info.bpp);
|
||||||
|
write_reg(BGA_REG_XRES, var_info.xres);
|
||||||
|
write_reg(BGA_REG_YRES, var_info.yres);
|
||||||
|
write_reg(BGA_REG_XRES_VIRT, var_info.xres_virt);
|
||||||
|
write_reg(BGA_REG_YRES_VIRT, var_info.yres_virt);
|
||||||
|
|
||||||
|
const bool valid_config =
|
||||||
|
read_reg(BGA_REG_BPP) == var_info.bpp &&
|
||||||
|
read_reg(BGA_REG_XRES) == var_info.xres &&
|
||||||
|
read_reg(BGA_REG_YRES) == var_info.yres &&
|
||||||
|
read_reg(BGA_REG_XRES_VIRT) == var_info.xres_virt;
|
||||||
|
|
||||||
|
if (!valid_config)
|
||||||
|
{
|
||||||
|
write_reg(BGA_REG_BPP, m_var_info.bpp);
|
||||||
|
write_reg(BGA_REG_XRES, m_var_info.xres);
|
||||||
|
write_reg(BGA_REG_YRES, m_var_info.yres);
|
||||||
|
write_reg(BGA_REG_XRES_VIRT, m_var_info.xres_virt);
|
||||||
|
write_reg(BGA_REG_YRES_VIRT, m_var_info.yres_virt);
|
||||||
|
|
||||||
|
write_reg(BGA_REG_ENABLE, BGA_ENABLE_NOCLEARMEM | old_enable);
|
||||||
|
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_reg(BGA_REG_ENABLE, BGA_ENABLE_LFB_ENABLE | BGA_ENABLE_ENABLE);
|
||||||
|
|
||||||
|
// NOTE: At least qemu only sets virtual yres on enable and it will be
|
||||||
|
// maximum that fits within vram. Our initial bounds check should
|
||||||
|
// make sure this always succeeds
|
||||||
|
ASSERT(read_reg(BGA_REG_YRES_VIRT) >= var_info.yres_virt);
|
||||||
|
|
||||||
|
write_reg(BGA_REG_XOFF, var_info.xoff);
|
||||||
|
write_reg(BGA_REG_YOFF, var_info.yoff);
|
||||||
|
|
||||||
|
m_var_info = var_info;
|
||||||
|
m_fix_info.pitch = m_var_info.xres_virt * m_var_info.bpp / 8;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void BGAController::write_reg(uint16_t reg, uint16_t value)
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
IO::outw(BGA_IO_PORT_INDEX, reg);
|
||||||
|
IO::outw(BGA_IO_PORT_DATA, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t BGAController::read_reg(uint16_t reg)
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
IO::outw(BGA_IO_PORT_INDEX, reg);
|
||||||
|
return IO::inw(BGA_IO_PORT_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_fix_info BGAController::get_fb_fix_info() const
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
return m_fix_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_var_info BGAController::get_fb_var_info() const
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
return m_var_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
#include <BAN/Array.h>
|
#include <BAN/Array.h>
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
|
#include <kernel/GDT.h>
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/InterruptController.h>
|
#include <kernel/InterruptController.h>
|
||||||
|
#include <kernel/InterruptNumbers.h>
|
||||||
#include <kernel/InterruptStack.h>
|
#include <kernel/InterruptStack.h>
|
||||||
#include <kernel/Memory/kmalloc.h>
|
#include <kernel/Memory/kmalloc.h>
|
||||||
#include <kernel/Panic.h>
|
#include <kernel/Panic.h>
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
#include <kernel/FS/DevFS/FileSystem.h>
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
#include <kernel/Input/InputDevice.h>
|
#include <kernel/Input/InputDevice.h>
|
||||||
#include <kernel/Lock/BlockableSpinLock.h>
|
#include <kernel/Lock/BlockableSpinLock.h>
|
||||||
|
#include <kernel/Scheduler.h>
|
||||||
#include <kernel/Terminal/TTY.h>
|
#include <kernel/Terminal/TTY.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
|
|
||||||
#include <LibInput/Joystick.h>
|
#include <LibInput/Joystick.h>
|
||||||
#include <LibInput/KeyEvent.h>
|
#include <LibInput/KeyEvent.h>
|
||||||
@@ -305,8 +307,7 @@ namespace Kernel
|
|||||||
BAN::ErrorOr<void> KeyboardDevice::initialize_tty_thread()
|
BAN::ErrorOr<void> KeyboardDevice::initialize_tty_thread()
|
||||||
{
|
{
|
||||||
auto* thread = TRY(Thread::create_kernel(tty_keyboard_thread, nullptr));
|
auto* thread = TRY(Thread::create_kernel(tty_keyboard_thread, nullptr));
|
||||||
ASSERT(thread);
|
Processor::scheduler().add_thread(thread);
|
||||||
TRY(Processor::scheduler().add_thread(thread));
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include <kernel/Input/PS2/Keyboard.h>
|
#include <kernel/Input/PS2/Keyboard.h>
|
||||||
#include <kernel/Input/PS2/Mouse.h>
|
#include <kernel/Input/PS2/Mouse.h>
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
|
#include <kernel/Scheduler.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
namespace Kernel::Input
|
namespace Kernel::Input
|
||||||
@@ -317,11 +319,18 @@ namespace Kernel::Input
|
|||||||
if (crs_obj == nullptr)
|
if (crs_obj == nullptr)
|
||||||
return PS2ResourceSetting {};
|
return PS2ResourceSetting {};
|
||||||
|
|
||||||
|
const auto crs = TRY(ACPI::AML::evaluate_node(crs_path, crs_obj->node));
|
||||||
|
if (crs.type != ACPI::AML::Node::Type::Buffer)
|
||||||
|
{
|
||||||
|
dwarnln("PS/2 _CRS is not a buffer, but {}", crs);
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
PS2ResourceSetting result;
|
PS2ResourceSetting result;
|
||||||
result.type = type;
|
result.type = type;
|
||||||
|
|
||||||
BAN::Optional<ACPI::ResourceData> data;
|
BAN::Optional<ACPI::ResourceData> data;
|
||||||
ACPI::ResourceParser parser({ crs_obj->node.as.str_buf->bytes, static_cast<size_t>(crs_obj->node.as.str_buf->size) });
|
ACPI::ResourceParser parser({ crs.as.str_buf->bytes, static_cast<size_t>(crs.as.str_buf->size) });
|
||||||
while ((data = parser.get_next()).has_value())
|
while ((data = parser.get_next()).has_value())
|
||||||
{
|
{
|
||||||
switch (data->type)
|
switch (data->type)
|
||||||
@@ -345,7 +354,7 @@ namespace Kernel::Input
|
|||||||
result.command_port = data->as.fixed_io_port.range_base;
|
result.command_port = data->as.fixed_io_port.range_base;
|
||||||
break;
|
break;
|
||||||
case ACPI::ResourceData::Type::IRQ:
|
case ACPI::ResourceData::Type::IRQ:
|
||||||
if (__builtin_popcount(data->as.irq.irq_mask) != 1)
|
if (BAN::Math::popcount(data->as.irq.irq_mask) != 1)
|
||||||
break;
|
break;
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
if (data->as.irq.irq_mask & (1 << i))
|
if (data->as.irq.irq_mask & (1 << i))
|
||||||
@@ -386,14 +395,11 @@ namespace Kernel::Input
|
|||||||
}
|
}
|
||||||
|
|
||||||
dprintln("Found {} PS/2 devices from ACPI namespace", acpi_devices.size());
|
dprintln("Found {} PS/2 devices from ACPI namespace", acpi_devices.size());
|
||||||
if (acpi_devices.empty())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
if (acpi_devices.size() > 2)
|
if (acpi_devices.size() > 2)
|
||||||
{
|
{
|
||||||
dwarnln("TODO: over 2 PS/2 devices");
|
dwarnln("TODO: over 2 PS/2 devices");
|
||||||
while (acpi_devices.size() > 2)
|
MUST(acpi_devices.resize(2));
|
||||||
acpi_devices.pop_back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acpi_devices.size() == 2)
|
if (acpi_devices.size() == 2)
|
||||||
@@ -419,34 +425,35 @@ namespace Kernel::Input
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::Optional<uint16_t> command_port;
|
if (!acpi_devices.empty())
|
||||||
command_port = acpi_devices[0].command_port;
|
|
||||||
if (!command_port.has_value() && acpi_devices.size() >= 2)
|
|
||||||
command_port = acpi_devices[1].command_port;
|
|
||||||
if (command_port.has_value())
|
|
||||||
m_command_port = command_port.value();
|
|
||||||
|
|
||||||
BAN::Optional<uint16_t> data_port;
|
|
||||||
data_port = acpi_devices[0].data_port;
|
|
||||||
if (!data_port.has_value() && acpi_devices.size() >= 2)
|
|
||||||
data_port = acpi_devices[1].data_port;
|
|
||||||
if (data_port.has_value())
|
|
||||||
m_data_port = data_port.value();
|
|
||||||
|
|
||||||
devices[0] = {
|
|
||||||
.type = acpi_devices[0].type,
|
|
||||||
.interrupt = acpi_devices[0].irq.value_or(PS2::IRQ::DEVICE0)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (acpi_devices.size() > 1)
|
|
||||||
{
|
{
|
||||||
devices[1] = {
|
BAN::Optional<uint16_t> command_port;
|
||||||
.type = acpi_devices[1].type,
|
command_port = acpi_devices[0].command_port;
|
||||||
.interrupt = acpi_devices[1].irq.value_or(PS2::IRQ::DEVICE1)
|
if (!command_port.has_value() && acpi_devices.size() >= 2)
|
||||||
|
command_port = acpi_devices[1].command_port;
|
||||||
|
if (command_port.has_value())
|
||||||
|
m_command_port = command_port.value();
|
||||||
|
|
||||||
|
BAN::Optional<uint16_t> data_port;
|
||||||
|
data_port = acpi_devices[0].data_port;
|
||||||
|
if (!data_port.has_value() && acpi_devices.size() >= 2)
|
||||||
|
data_port = acpi_devices[1].data_port;
|
||||||
|
if (data_port.has_value())
|
||||||
|
m_data_port = data_port.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < acpi_devices.size(); i++)
|
||||||
|
{
|
||||||
|
devices[i] = {
|
||||||
|
.type = acpi_devices[i].type,
|
||||||
|
.interrupt = acpi_devices[i].irq.value_or(i == 0 ? PS2::IRQ::DEVICE0 : PS2::IRQ::DEVICE1),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (has_legacy_8042())
|
|
||||||
|
if (devices[0].type != DeviceType::None)
|
||||||
|
;
|
||||||
|
else if (scancode_set || has_legacy_8042())
|
||||||
{
|
{
|
||||||
devices[0] = {
|
devices[0] = {
|
||||||
.type = DeviceType::Unknown,
|
.type = DeviceType::Unknown,
|
||||||
@@ -551,7 +558,7 @@ namespace Kernel::Input
|
|||||||
static_cast<PS2DeviceInitInfo*>(info)->controller->device_initialize_task(info);
|
static_cast<PS2DeviceInitInfo*>(info)->controller->device_initialize_task(info);
|
||||||
}, &info
|
}, &info
|
||||||
));
|
));
|
||||||
TRY(Processor::scheduler().add_thread(init_thread));
|
Processor::scheduler().add_thread(init_thread);
|
||||||
|
|
||||||
while (!info.thread_started)
|
while (!info.thread_started)
|
||||||
Processor::pause();
|
Processor::pause();
|
||||||
|
|||||||
@@ -53,8 +53,9 @@ namespace Kernel::Input
|
|||||||
|
|
||||||
if (command_data[0] == Command::CONFIG_SCANCODE_SET && m_scancode_set >= 0xFE)
|
if (command_data[0] == Command::CONFIG_SCANCODE_SET && m_scancode_set >= 0xFE)
|
||||||
{
|
{
|
||||||
dwarnln("Could not detect scancode set, assuming 2");
|
dwarnln("Could not detect scancode set, assuming 1");
|
||||||
m_scancode_set = 2;
|
m_scancode_set_uncertain = true;
|
||||||
|
m_scancode_set = 1;
|
||||||
m_keymap.initialize(m_scancode_set);
|
m_keymap.initialize(m_scancode_set);
|
||||||
append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING, 0);
|
append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING, 0);
|
||||||
}
|
}
|
||||||
@@ -89,6 +90,7 @@ namespace Kernel::Input
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
dwarnln("Could not detect scancode set, assuming 1");
|
dwarnln("Could not detect scancode set, assuming 1");
|
||||||
|
m_scancode_set_uncertain = true;
|
||||||
m_scancode_set = 1;
|
m_scancode_set = 1;
|
||||||
}
|
}
|
||||||
m_keymap.initialize(m_scancode_set);
|
m_keymap.initialize(m_scancode_set);
|
||||||
@@ -103,6 +105,17 @@ namespace Kernel::Input
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we could not detect scancode set, we assume it to be 1
|
||||||
|
// If we get byte 0xF0 which is indicates release in scancode set 2
|
||||||
|
// and nothing in scancode set 1, switch to scancode set 2
|
||||||
|
if (m_scancode_set_uncertain && byte == 0xF0)
|
||||||
|
{
|
||||||
|
dprintln("Switching to scancode set 2");
|
||||||
|
m_scancode_set_uncertain = false;
|
||||||
|
m_scancode_set = 2;
|
||||||
|
m_keymap.initialize(m_scancode_set);
|
||||||
|
}
|
||||||
|
|
||||||
m_byte_buffer[m_byte_index++] = byte;
|
m_byte_buffer[m_byte_index++] = byte;
|
||||||
if (byte == 0xE0)
|
if (byte == 0xE0)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
#include <kernel/Lock/Mutex.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
bool Mutex::try_lock()
|
||||||
|
{
|
||||||
|
const auto tid = Thread::current_tid();
|
||||||
|
if (tid == m_locker)
|
||||||
|
ASSERT(m_lock_depth > 0);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pid_t expected = -1;
|
||||||
|
if (!m_locker.compare_exchange(expected, tid))
|
||||||
|
return false;
|
||||||
|
ASSERT(m_lock_depth == 0);
|
||||||
|
if (tid)
|
||||||
|
Thread::current().add_mutex();
|
||||||
|
}
|
||||||
|
m_lock_depth++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mutex::lock()
|
||||||
|
{
|
||||||
|
const auto tid = Thread::current_tid();
|
||||||
|
if (tid == m_locker)
|
||||||
|
ASSERT(m_lock_depth > 0);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(!tid || !Thread::current().has_spinlock());
|
||||||
|
pid_t expected = -1;
|
||||||
|
while (!m_locker.compare_exchange(expected, tid))
|
||||||
|
{
|
||||||
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||||
|
Processor::yield();
|
||||||
|
expected = -1;
|
||||||
|
}
|
||||||
|
ASSERT(m_lock_depth == 0);
|
||||||
|
if (tid)
|
||||||
|
Thread::current().add_mutex();
|
||||||
|
}
|
||||||
|
m_lock_depth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mutex::unlock()
|
||||||
|
{
|
||||||
|
const auto tid = Thread::current_tid();
|
||||||
|
ASSERT(m_locker == tid);
|
||||||
|
ASSERT(m_lock_depth > 0);
|
||||||
|
if (--m_lock_depth == 0)
|
||||||
|
{
|
||||||
|
m_locker = -1;
|
||||||
|
if (tid)
|
||||||
|
Thread::current().remove_mutex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mutex::is_locked_by_current_thread() const
|
||||||
|
{
|
||||||
|
return m_locker == Thread::current_tid();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PriorityMutex::try_lock()
|
||||||
|
{
|
||||||
|
const auto tid = Thread::current_tid();
|
||||||
|
|
||||||
|
if (tid == m_locker)
|
||||||
|
ASSERT(m_lock_depth > 0);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
||||||
|
pid_t expected = -1;
|
||||||
|
if (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(expected, tid))
|
||||||
|
return false;
|
||||||
|
if (has_priority)
|
||||||
|
m_queue_length++;
|
||||||
|
ASSERT(m_lock_depth == 0);
|
||||||
|
if (tid)
|
||||||
|
Thread::current().add_mutex();
|
||||||
|
}
|
||||||
|
m_lock_depth++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriorityMutex::lock()
|
||||||
|
{
|
||||||
|
const auto tid = Thread::current_tid();
|
||||||
|
|
||||||
|
if (tid == m_locker)
|
||||||
|
ASSERT(m_lock_depth > 0);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(!tid || !Thread::current().has_spinlock());
|
||||||
|
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
||||||
|
if (has_priority)
|
||||||
|
m_queue_length++;
|
||||||
|
pid_t expected = -1;
|
||||||
|
while (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(expected, tid))
|
||||||
|
{
|
||||||
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||||
|
Processor::yield();
|
||||||
|
expected = -1;
|
||||||
|
}
|
||||||
|
ASSERT(m_lock_depth == 0);
|
||||||
|
if (tid)
|
||||||
|
Thread::current().add_mutex();
|
||||||
|
}
|
||||||
|
m_lock_depth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriorityMutex::unlock()
|
||||||
|
{
|
||||||
|
const auto tid = Thread::current_tid();
|
||||||
|
ASSERT(m_locker == tid);
|
||||||
|
ASSERT(m_lock_depth > 0);
|
||||||
|
if (--m_lock_depth == 0)
|
||||||
|
{
|
||||||
|
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
||||||
|
if (has_priority)
|
||||||
|
m_queue_length--;
|
||||||
|
m_locker = -1;
|
||||||
|
if (tid)
|
||||||
|
Thread::current().remove_mutex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PriorityMutex::is_locked_by_current_thread() const
|
||||||
|
{
|
||||||
|
return m_locker == Thread::current_tid();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
#include <kernel/Lock/BlockableSpinLock.h>
|
||||||
|
#include <kernel/Lock/RWLock.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
void RWLock::rd_lock()
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
while (m_writers_waiting > 0 || m_writer != -1)
|
||||||
|
{
|
||||||
|
BlockableSpinLock block(m_lock);
|
||||||
|
m_thread_blocker.block_indefinite(&block);
|
||||||
|
}
|
||||||
|
m_readers_active++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWLock::rd_unlock()
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
if (--m_readers_active == 0)
|
||||||
|
m_thread_blocker.unblock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWLock::wr_lock()
|
||||||
|
{
|
||||||
|
if (m_writer == Thread::current_tid())
|
||||||
|
{
|
||||||
|
m_writer_depth++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
m_writers_waiting++;
|
||||||
|
while (m_readers_active > 0 || m_writer != -1)
|
||||||
|
{
|
||||||
|
BlockableSpinLock block(m_lock);
|
||||||
|
m_thread_blocker.block_indefinite(&block);
|
||||||
|
}
|
||||||
|
m_writers_waiting--;
|
||||||
|
|
||||||
|
m_writer = Thread::current_tid();
|
||||||
|
m_writer_depth = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWLock::wr_unlock()
|
||||||
|
{
|
||||||
|
if (--m_writer_depth != 0)
|
||||||
|
return;
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
m_writer = -1;
|
||||||
|
m_thread_blocker.unblock();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -115,7 +115,7 @@ namespace Kernel
|
|||||||
return {};
|
return {};
|
||||||
|
|
||||||
const vaddr_t first_page = BAN::Math::max(m_vaddr, address) & PAGE_ADDR_MASK;
|
const vaddr_t first_page = BAN::Math::max(m_vaddr, address) & PAGE_ADDR_MASK;
|
||||||
const vaddr_t last_page = BAN::Math::div_round_up(BAN::Math::min(m_vaddr + m_size, address + size), PAGE_SIZE) * PAGE_SIZE;
|
const vaddr_t last_page = BAN::Math::div_round_up<vaddr_t>(BAN::Math::min(m_vaddr + m_size, address + size), PAGE_SIZE) * PAGE_SIZE;
|
||||||
|
|
||||||
RWLockRDGuard _(m_shared_data->rw_lock);
|
RWLockRDGuard _(m_shared_data->rw_lock);
|
||||||
for (vaddr_t page_addr = first_page; page_addr < last_page; page_addr += PAGE_SIZE)
|
for (vaddr_t page_addr = first_page; page_addr < last_page; page_addr += PAGE_SIZE)
|
||||||
|
|||||||
@@ -43,11 +43,10 @@ namespace Kernel
|
|||||||
PageTable::with_per_cpu_fast_page(current_paddr, [&page_matched_bit](void* addr) {
|
PageTable::with_per_cpu_fast_page(current_paddr, [&page_matched_bit](void* addr) {
|
||||||
for (size_t j = 0; j < PAGE_SIZE / sizeof(size_t); j++)
|
for (size_t j = 0; j < PAGE_SIZE / sizeof(size_t); j++)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(size_t) == sizeof(long));
|
|
||||||
auto& current = static_cast<size_t*>(addr)[j];
|
auto& current = static_cast<size_t*>(addr)[j];
|
||||||
if (current == BAN::numeric_limits<size_t>::max())
|
if (current == BAN::numeric_limits<size_t>::max())
|
||||||
continue;
|
continue;
|
||||||
const int ctz = __builtin_ctzl(~current);
|
const int ctz = BAN::Math::ctz(~current);
|
||||||
current |= static_cast<size_t>(1) << ctz;
|
current |= static_cast<size_t>(1) << ctz;
|
||||||
page_matched_bit = j * sizeof(size_t) * 8 + ctz;
|
page_matched_bit = j * sizeof(size_t) * 8 + ctz;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -87,13 +87,24 @@ namespace Kernel
|
|||||||
return BAN::Error::from_errno(ENOENT);
|
return BAN::Error::from_errno(ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
const auto& process = Process::current();
|
const auto& process = Process::current();
|
||||||
const uid_t uid = process.credentials().euid();
|
const uid_t uid = process.credentials().euid();
|
||||||
const gid_t gid = process.credentials().egid();
|
const gid_t gid = process.credentials().egid();
|
||||||
const pid_t pid = process.pid();
|
const pid_t pid = process.pid();
|
||||||
const mode_t mode = shmflg & 0777;
|
const mode_t mode = shmflg & 0777;
|
||||||
|
|
||||||
auto object = TRY(BAN::RefPtr<Object>::create(key, shmid_ds {
|
const int shmid = ({
|
||||||
|
int id;
|
||||||
|
do {
|
||||||
|
id = Random::get<unsigned>() & BAN::numeric_limits<int>::max();
|
||||||
|
} while (m_ids.contains(shmid));
|
||||||
|
id;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto object = TRY(BAN::RefPtr<Object>::create(key, shmid, shmid_ds {
|
||||||
.shm_perm = {
|
.shm_perm = {
|
||||||
.uid = uid,
|
.uid = uid,
|
||||||
.gid = gid,
|
.gid = gid,
|
||||||
@@ -109,13 +120,7 @@ namespace Kernel
|
|||||||
.shm_dtime = 0,
|
.shm_dtime = 0,
|
||||||
.shm_ctime = SystemTimer::get().real_time().tv_sec,
|
.shm_ctime = SystemTimer::get().real_time().tv_sec,
|
||||||
}));
|
}));
|
||||||
TRY(object->paddrs.resize(BAN::Math::div_round_up(size, PAGE_SIZE), 0));
|
TRY(object->paddrs.resize(BAN::Math::div_round_up<size_t>(size, PAGE_SIZE), 0));
|
||||||
|
|
||||||
auto generate_id = []() { return Random::get<unsigned>() & BAN::numeric_limits<int>::max(); };
|
|
||||||
|
|
||||||
int shmid = generate_id();
|
|
||||||
while (m_ids.contains(shmid))
|
|
||||||
shmid = generate_id();
|
|
||||||
|
|
||||||
if (key != IPC_PRIVATE)
|
if (key != IPC_PRIVATE)
|
||||||
TRY(m_ids.insert(key, shmid));
|
TRY(m_ids.insert(key, shmid));
|
||||||
@@ -222,14 +227,16 @@ namespace Kernel
|
|||||||
LockGuard _(m_object->mutex);
|
LockGuard _(m_object->mutex);
|
||||||
m_object->info.shm_nattch++;
|
m_object->info.shm_nattch++;
|
||||||
m_object->info.shm_atime = SystemTimer::get().real_time().tv_sec;
|
m_object->info.shm_atime = SystemTimer::get().real_time().tv_sec;
|
||||||
|
m_object->info.shm_lpid = Process::current().pid();
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedMemoryObject::~SharedMemoryObject()
|
SharedMemoryObject::~SharedMemoryObject()
|
||||||
{
|
{
|
||||||
LockGuard _(m_object->mutex);
|
LockGuard _(m_object->mutex);
|
||||||
if (--m_object->info.shm_nattch == 0 && m_object->marked_for_deletion)
|
if (--m_object->info.shm_nattch == 0 && m_object->marked_for_deletion)
|
||||||
SharedMemoryObjectManager::get().m_objects.remove(m_object->key);
|
SharedMemoryObjectManager::get().m_objects.remove(m_object->id);
|
||||||
m_object->info.shm_dtime = SystemTimer::get().real_time().tv_sec;
|
m_object->info.shm_dtime = SystemTimer::get().real_time().tv_sec;
|
||||||
|
m_object->info.shm_lpid = Process::current().pid();
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> SharedMemoryObject::clone(PageTable& new_page_table)
|
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> SharedMemoryObject::clone(PageTable& new_page_table)
|
||||||
|
|||||||
@@ -125,8 +125,6 @@ struct BitmapAllocator
|
|||||||
// NOTE: We could optimize other bitmap functions than this
|
// NOTE: We could optimize other bitmap functions than this
|
||||||
// but this one is the bottle neck so it doesn't matter
|
// but this one is the bottle neck so it doesn't matter
|
||||||
|
|
||||||
static_assert(sizeof(unsigned long long) == sizeof(uint64_t));
|
|
||||||
|
|
||||||
if (index >= total_chunks)
|
if (index >= total_chunks)
|
||||||
return index;
|
return index;
|
||||||
|
|
||||||
@@ -134,7 +132,7 @@ struct BitmapAllocator
|
|||||||
{
|
{
|
||||||
const uint64_t qword = *reinterpret_cast<const uint64_t*>(base + (index - rem) / 8) >> rem;
|
const uint64_t qword = *reinterpret_cast<const uint64_t*>(base + (index - rem) / 8) >> rem;
|
||||||
if (qword != (1ull << (64 - rem)) - 1)
|
if (qword != (1ull << (64 - rem)) - 1)
|
||||||
return index + __builtin_ctzll(~qword);
|
return index + BAN::Math::ctz(~qword);
|
||||||
index += 64 - rem;
|
index += 64 - rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +140,7 @@ struct BitmapAllocator
|
|||||||
{
|
{
|
||||||
const uint64_t qword = *reinterpret_cast<const uint64_t*>(base + index / 8);
|
const uint64_t qword = *reinterpret_cast<const uint64_t*>(base + index / 8);
|
||||||
if (qword != UINT64_MAX)
|
if (qword != UINT64_MAX)
|
||||||
return index + __builtin_ctzll(~qword);
|
return index + BAN::Math::ctz(~qword);
|
||||||
index += 64;
|
index += 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
#include <kernel/MMIO.h>
|
#include <kernel/MMIO.h>
|
||||||
#include <kernel/Networking/E1000/E1000.h>
|
#include <kernel/Networking/E1000/E1000.h>
|
||||||
#include <kernel/Networking/NetworkManager.h>
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
|
#include <kernel/Scheduler.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
@@ -93,11 +95,8 @@ namespace Kernel
|
|||||||
auto* thread = TRY(Thread::create_kernel([](void* e1000_ptr) {
|
auto* thread = TRY(Thread::create_kernel([](void* e1000_ptr) {
|
||||||
static_cast<E1000*>(e1000_ptr)->receive_thread();
|
static_cast<E1000*>(e1000_ptr)->receive_thread();
|
||||||
}, this));
|
}, this));
|
||||||
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error())
|
|
||||||
{
|
Processor::scheduler().add_thread(thread);
|
||||||
delete thread;
|
|
||||||
return ret.release_error();
|
|
||||||
}
|
|
||||||
m_thread_is_dead = false;
|
m_thread_is_dead = false;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include <kernel/Lock/BlockableSpinLock.h>
|
#include <kernel/Lock/BlockableSpinLock.h>
|
||||||
#include <kernel/Networking/Loopback.h>
|
#include <kernel/Networking/Loopback.h>
|
||||||
#include <kernel/Networking/NetworkManager.h>
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
|
#include <kernel/Scheduler.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
@@ -23,11 +25,8 @@ namespace Kernel
|
|||||||
auto* thread = TRY(Thread::create_kernel([](void* loopback_ptr) {
|
auto* thread = TRY(Thread::create_kernel([](void* loopback_ptr) {
|
||||||
static_cast<LoopbackInterface*>(loopback_ptr)->receive_thread();
|
static_cast<LoopbackInterface*>(loopback_ptr)->receive_thread();
|
||||||
}, loopback_ptr));
|
}, loopback_ptr));
|
||||||
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error())
|
|
||||||
{
|
Processor::scheduler().add_thread(thread);
|
||||||
delete thread;
|
|
||||||
return ret.release_error();
|
|
||||||
}
|
|
||||||
loopback->m_thread_is_dead = false;
|
loopback->m_thread_is_dead = false;
|
||||||
|
|
||||||
loopback->set_ipv4_address({ 127, 0, 0, 1 });
|
loopback->set_ipv4_address({ 127, 0, 0, 1 });
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#include <kernel/Networking/NetworkManager.h>
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
#include <kernel/Networking/RTL8169/Definitions.h>
|
#include <kernel/Networking/RTL8169/Definitions.h>
|
||||||
#include <kernel/Networking/RTL8169/RTL8169.h>
|
#include <kernel/Networking/RTL8169/RTL8169.h>
|
||||||
|
#include <kernel/Scheduler.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
@@ -73,11 +75,8 @@ namespace Kernel
|
|||||||
auto* thread = TRY(Thread::create_kernel([](void* rtl8169_ptr) {
|
auto* thread = TRY(Thread::create_kernel([](void* rtl8169_ptr) {
|
||||||
static_cast<RTL8169*>(rtl8169_ptr)->receive_thread();
|
static_cast<RTL8169*>(rtl8169_ptr)->receive_thread();
|
||||||
}, this));
|
}, this));
|
||||||
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error())
|
|
||||||
{
|
Processor::scheduler().add_thread(thread);
|
||||||
delete thread;
|
|
||||||
return ret.release_error();
|
|
||||||
}
|
|
||||||
m_rx_thread_is_dead = false;
|
m_rx_thread_is_dead = false;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <kernel/Networking/TCPSocket.h>
|
#include <kernel/Networking/TCPSocket.h>
|
||||||
#include <kernel/Process.h>
|
#include <kernel/Process.h>
|
||||||
#include <kernel/Random.h>
|
#include <kernel/Random.h>
|
||||||
|
#include <kernel/Scheduler.h>
|
||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -44,7 +45,7 @@ namespace Kernel
|
|||||||
reinterpret_cast<TCPSocket*>(socket_ptr)->process_task();
|
reinterpret_cast<TCPSocket*>(socket_ptr)->process_task();
|
||||||
}, socket.ptr()
|
}, socket.ptr()
|
||||||
));
|
));
|
||||||
TRY(Processor::scheduler().add_thread(socket->m_thread));
|
Processor::scheduler().add_thread(socket->m_thread);
|
||||||
// hack to keep socket alive until its process starts
|
// hack to keep socket alive until its process starts
|
||||||
socket->ref();
|
socket->ref();
|
||||||
return socket;
|
return socket;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace Kernel
|
|||||||
|
|
||||||
static BAN::ErrorOr<BAN::StringView> validate_sockaddr_un(const sockaddr* address, socklen_t address_len)
|
static BAN::ErrorOr<BAN::StringView> validate_sockaddr_un(const sockaddr* address, socklen_t address_len)
|
||||||
{
|
{
|
||||||
if (address_len < static_cast<socklen_t>(sizeof(sa_family_t)))
|
if (address_len <= static_cast<socklen_t>(sizeof(sa_family_t)))
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
if (address_len > static_cast<socklen_t>(sizeof(sockaddr_un)))
|
if (address_len > static_cast<socklen_t>(sizeof(sockaddr_un)))
|
||||||
address_len = sizeof(sockaddr_un);
|
address_len = sizeof(sockaddr_un);
|
||||||
@@ -30,13 +30,12 @@ namespace Kernel
|
|||||||
if (sockaddr_un.sun_family != AF_UNIX)
|
if (sockaddr_un.sun_family != AF_UNIX)
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
size_t length = 0;
|
auto sun_path = BAN::StringView { sockaddr_un.sun_path, address_len - sizeof(sa_family_t) };
|
||||||
while (length < sizeof(sockaddr_un::sun_path) && sockaddr_un.sun_path[length])
|
if (const auto null_idx = sun_path.find('\0'); null_idx.has_value())
|
||||||
length++;
|
sun_path = sun_path.substring(0, null_idx.value());
|
||||||
if (length >= sizeof(sockaddr_un::sun_path))
|
if (sun_path.empty())
|
||||||
return BAN::Error::from_errno(ENAMETOOLONG);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
return sun_path;
|
||||||
return BAN::StringView { sockaddr_un.sun_path, length };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> UnixDomainSocket::create(Socket::Type socket_type, const Socket::Info& info)
|
BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> UnixDomainSocket::create(Socket::Type socket_type, const Socket::Info& info)
|
||||||
@@ -264,14 +263,15 @@ namespace Kernel
|
|||||||
BAN::ErrorOr<void> UnixDomainSocket::bind_impl(const sockaddr* address, socklen_t address_len)
|
BAN::ErrorOr<void> UnixDomainSocket::bind_impl(const sockaddr* address, socklen_t address_len)
|
||||||
{
|
{
|
||||||
const auto sun_path = TRY(validate_sockaddr_un(address, address_len));
|
const auto sun_path = TRY(validate_sockaddr_un(address, address_len));
|
||||||
if (sun_path.empty())
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
BAN::String sun_path_nul;
|
||||||
|
TRY(sun_path_nul.append(sun_path));
|
||||||
|
|
||||||
// FIXME: This feels sketchy
|
// FIXME: This feels sketchy
|
||||||
auto parent_file = sun_path.front() == '/'
|
auto parent_file = sun_path.front() == '/'
|
||||||
? TRY(Process::current().root_file().clone())
|
? TRY(Process::current().root_file().clone())
|
||||||
: TRY(Process::current().working_directory().clone());
|
: TRY(Process::current().working_directory().clone());
|
||||||
if (auto ret = Process::current().create_file(AT_FDCWD, sun_path.data(), 0755 | Inode::Mode::IFSOCK); ret.is_error())
|
if (auto ret = Process::current().create_file(AT_FDCWD, sun_path_nul.data(), 0755 | Inode::Mode::IFSOCK); ret.is_error())
|
||||||
{
|
{
|
||||||
if (ret.error().get_error_code() == EEXIST)
|
if (ret.error().get_error_code() == EEXIST)
|
||||||
return BAN::Error::from_errno(EADDRINUSE);
|
return BAN::Error::from_errno(EADDRINUSE);
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace Kernel
|
|||||||
if (flags & ~(O_ACCMODE | O_NOFOLLOW | O_APPEND | O_TRUNC | O_CLOEXEC | O_TTY_INIT | O_NOCTTY | O_DIRECTORY | O_CREAT | O_EXCL | O_NONBLOCK))
|
if (flags & ~(O_ACCMODE | O_NOFOLLOW | O_APPEND | O_TRUNC | O_CLOEXEC | O_TTY_INIT | O_NOCTTY | O_DIRECTORY | O_CREAT | O_EXCL | O_NONBLOCK))
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
|
||||||
if ((flags & O_ACCMODE) != O_RDWR && __builtin_popcount(flags & O_ACCMODE) != 1)
|
if ((flags & O_ACCMODE) != O_RDWR && BAN::Math::popcount<unsigned>(flags & O_ACCMODE) != 1)
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
if ((flags & O_DIRECTORY) && !file.inode->mode().ifdir())
|
if ((flags & O_DIRECTORY) && !file.inode->mode().ifdir())
|
||||||
|
|||||||
+19
-5
@@ -3,6 +3,7 @@
|
|||||||
#include <kernel/ACPI/ACPI.h>
|
#include <kernel/ACPI/ACPI.h>
|
||||||
#include <kernel/APIC.h>
|
#include <kernel/APIC.h>
|
||||||
#include <kernel/Audio/Controller.h>
|
#include <kernel/Audio/Controller.h>
|
||||||
|
#include <kernel/Graphics/BGA.h>
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
@@ -258,6 +259,13 @@ namespace Kernel::PCI
|
|||||||
for_each_device(
|
for_each_device(
|
||||||
[&](PCI::Device& pci_device)
|
[&](PCI::Device& pci_device)
|
||||||
{
|
{
|
||||||
|
if (pci_device.vendor_id() == 0x1234 && pci_device.device_id() == 0x1111)
|
||||||
|
{
|
||||||
|
if (auto ret = BGAController::create(pci_device); ret.is_error())
|
||||||
|
dprintln("BGA: {}", ret.error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (pci_device.class_code())
|
switch (pci_device.class_code())
|
||||||
{
|
{
|
||||||
case 0x01:
|
case 0x01:
|
||||||
@@ -912,10 +920,10 @@ namespace Kernel::PCI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// disable io/mem space while reading bar
|
// disable io/mem space while reading bar
|
||||||
uint16_t command = device.read_word(PCI_REG_COMMAND);
|
const uint16_t command = device.read_word(PCI_REG_COMMAND);
|
||||||
device.write_word(PCI_REG_COMMAND, command & ~(PCI_CMD_IO_SPACE | PCI_CMD_MEM_SPACE));
|
device.write_word(PCI_REG_COMMAND, command & ~(PCI_CMD_IO_SPACE | PCI_CMD_MEM_SPACE));
|
||||||
|
|
||||||
uint8_t offset = 0x10 + bar_num * 4;
|
const uint8_t offset = 0x10 + bar_num * 4;
|
||||||
|
|
||||||
uint64_t addr = device.read_dword(offset);
|
uint64_t addr = device.read_dword(offset);
|
||||||
|
|
||||||
@@ -924,6 +932,13 @@ namespace Kernel::PCI
|
|||||||
size = ~size + 1;
|
size = ~size + 1;
|
||||||
device.write_dword(offset, addr);
|
device.write_dword(offset, addr);
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
device.write_word(PCI_REG_COMMAND, command);
|
||||||
|
dwarnln("BAR{} has size 0", bar_num);
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
// determine bar type
|
// determine bar type
|
||||||
BarType type = BarType::INVALID;
|
BarType type = BarType::INVALID;
|
||||||
if (addr & 1)
|
if (addr & 1)
|
||||||
@@ -956,8 +971,7 @@ namespace Kernel::PCI
|
|||||||
TRY(region->initialize());
|
TRY(region->initialize());
|
||||||
|
|
||||||
// restore old command register and enable correct IO/MEM space
|
// restore old command register and enable correct IO/MEM space
|
||||||
command |= (type == BarType::IO) ? PCI_CMD_IO_SPACE : PCI_CMD_MEM_SPACE;
|
device.write_word(PCI_REG_COMMAND, command | ((type == BarType::IO) ? PCI_CMD_IO_SPACE : PCI_CMD_MEM_SPACE));
|
||||||
device.write_word(PCI_REG_COMMAND, command);
|
|
||||||
|
|
||||||
#if DEBUG_PCI
|
#if DEBUG_PCI
|
||||||
dprintln("created BAR region for PCI {2H}:{2H}.{2H}",
|
dprintln("created BAR region for PCI {2H}:{2H}.{2H}",
|
||||||
@@ -997,7 +1011,7 @@ namespace Kernel::PCI
|
|||||||
if (m_type == BarType::IO)
|
if (m_type == BarType::IO)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
|
const size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
|
||||||
m_vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
|
m_vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
|
||||||
if (m_vaddr == 0)
|
if (m_vaddr == 0)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
|
#include <kernel/InterruptNumbers.h>
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
#include <kernel/PIC.h>
|
#include <kernel/PIC.h>
|
||||||
|
|
||||||
|
|||||||
+111
-121
@@ -237,9 +237,8 @@ namespace Kernel
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: make sure the last two `MUST`s don't fail
|
// NOTE: make sure the last `MUST` doesn't fail
|
||||||
TRY(process->m_threads.reserve(1));
|
TRY(process->m_threads.reserve(1));
|
||||||
TRY(Processor::scheduler().bind_thread_to_processor(thread, Processor::current_id()));
|
|
||||||
|
|
||||||
{
|
{
|
||||||
SpinLockGuard _(s_process_lock);
|
SpinLockGuard _(s_process_lock);
|
||||||
@@ -247,7 +246,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
|
|
||||||
MUST(process->m_threads.push_back(thread));
|
MUST(process->m_threads.push_back(thread));
|
||||||
MUST(Processor::scheduler().add_thread(thread));
|
Processor::scheduler().add_thread(thread);
|
||||||
|
|
||||||
process_deleter.disable();
|
process_deleter.disable();
|
||||||
thread_deleter.disable();
|
thread_deleter.disable();
|
||||||
@@ -696,19 +695,24 @@ namespace Kernel
|
|||||||
|
|
||||||
size_t Process::proc_cputime(off_t offset, BAN::ByteSpan buffer) const
|
size_t Process::proc_cputime(off_t offset, BAN::ByteSpan buffer) const
|
||||||
{
|
{
|
||||||
const uint64_t cpu_time_ns = [this] {
|
uint64_t user_ns { 0 }, system_ns { 0 };
|
||||||
uint64_t cpu_time_ns { 0 };
|
|
||||||
|
{
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
for (auto* thread : m_threads)
|
for (auto* thread : m_threads)
|
||||||
cpu_time_ns += thread->cpu_time_ns();
|
{
|
||||||
return cpu_time_ns;
|
uint64_t u, s;
|
||||||
}();
|
thread->cpu_time_ns(u, s);
|
||||||
|
user_ns += u;
|
||||||
|
system_ns += s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto data = MUST(BAN::String::formatted("{}", cpu_time_ns));
|
auto data = MUST(BAN::String::formatted("{} {} {}", user_ns + system_ns, user_ns, system_ns));
|
||||||
if (static_cast<size_t>(offset) >= data.size() + 1)
|
if (static_cast<size_t>(offset) >= data.size())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const size_t to_copy = BAN::Math::min<size_t>(data.size() - offset + 1, buffer.size());
|
const size_t to_copy = BAN::Math::min<size_t>(data.size() - offset, buffer.size());
|
||||||
memcpy(buffer.data(), data.data(), to_copy);
|
memcpy(buffer.data(), data.data(), to_copy);
|
||||||
return to_copy;
|
return to_copy;
|
||||||
}
|
}
|
||||||
@@ -872,9 +876,8 @@ namespace Kernel
|
|||||||
Thread* thread = TRY(Thread::current().clone(forked, sp, ip));
|
Thread* thread = TRY(Thread::current().clone(forked, sp, ip));
|
||||||
BAN::ScopeGuard thread_deleter([thread] { delete thread; });
|
BAN::ScopeGuard thread_deleter([thread] { delete thread; });
|
||||||
|
|
||||||
// NOTE: make sure the last two `MUST`s don't fail
|
// NOTE: make sure the last `MUST` doesn't fail
|
||||||
TRY(forked->m_threads.reserve(1));
|
TRY(forked->m_threads.reserve(1));
|
||||||
TRY(Processor::scheduler().bind_thread_to_processor(thread, Processor::current_id()));
|
|
||||||
|
|
||||||
{
|
{
|
||||||
SpinLockGuard _(s_process_lock);
|
SpinLockGuard _(s_process_lock);
|
||||||
@@ -900,7 +903,7 @@ namespace Kernel
|
|||||||
ASSERT(this == &Process::current());
|
ASSERT(this == &Process::current());
|
||||||
|
|
||||||
MUST(forked->m_threads.push_back(thread));
|
MUST(forked->m_threads.push_back(thread));
|
||||||
MUST(Processor::scheduler().add_thread(thread));
|
Processor::scheduler().add_thread(thread);
|
||||||
|
|
||||||
process_deleter.disable();
|
process_deleter.disable();
|
||||||
thread_deleter.disable();
|
thread_deleter.disable();
|
||||||
@@ -1067,14 +1070,6 @@ namespace Kernel
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: bind new thread to this processor so it wont be rescheduled before end of this function
|
|
||||||
// and so that adding the thread to the scheduler cannot fail
|
|
||||||
if (auto ret = Scheduler::bind_thread_to_processor(new_thread, Processor::current_id()); ret.is_error())
|
|
||||||
{
|
|
||||||
Processor::set_interrupt_state(InterruptState::Enabled);
|
|
||||||
delete new_thread;
|
|
||||||
return ret.release_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
RWLockWRGuard wr_guard(m_memory_region_lock);
|
RWLockWRGuard wr_guard(m_memory_region_lock);
|
||||||
|
|
||||||
@@ -1098,7 +1093,9 @@ namespace Kernel
|
|||||||
m_threads.front()->m_process = nullptr;
|
m_threads.front()->m_process = nullptr;
|
||||||
m_threads.front()->give_keep_alive_page_table(BAN::move(m_page_table));
|
m_threads.front()->give_keep_alive_page_table(BAN::move(m_page_table));
|
||||||
|
|
||||||
MUST(Processor::scheduler().add_thread(new_thread));
|
// NOTE: bind new thread to this processor so it wont be rescheduled before end of this function
|
||||||
|
Scheduler::bind_thread_to_processor(new_thread, Processor::current_id());
|
||||||
|
Processor::scheduler().add_thread(new_thread);
|
||||||
m_threads.front() = new_thread;
|
m_threads.front() = new_thread;
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++)
|
for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++)
|
||||||
@@ -1265,18 +1262,12 @@ namespace Kernel
|
|||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryRegion* value_region = nullptr;
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
MemoryRegion* ovalue_region = nullptr;
|
BAN::ScopeGuard _([&] { for (auto* region : regions) region->unpin(); });
|
||||||
BAN::ScopeGuard _([&] {
|
|
||||||
if (value_region)
|
|
||||||
value_region->unpin();
|
|
||||||
if (ovalue_region)
|
|
||||||
ovalue_region->unpin();
|
|
||||||
});
|
|
||||||
|
|
||||||
value_region = TRY(validate_and_pin_pointer_access(value, sizeof(itimerval), false));
|
TRY(validate_and_pin_pointer_access(value, sizeof(itimerval), false, regions));
|
||||||
if (ovalue != nullptr)
|
if (ovalue != nullptr)
|
||||||
ovalue_region = TRY(validate_and_pin_pointer_access(ovalue, sizeof(itimerval), true));
|
TRY(validate_and_pin_pointer_access(ovalue, sizeof(itimerval), true, regions));
|
||||||
|
|
||||||
{
|
{
|
||||||
SpinLockGuard _(s_process_lock);
|
SpinLockGuard _(s_process_lock);
|
||||||
@@ -1470,8 +1461,10 @@ namespace Kernel
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, true));
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
BAN::ScopeGuard _([buffer_region] { buffer_region->unpin(); });
|
BAN::ScopeGuard _([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
TRY(validate_and_pin_pointer_access(buffer, count, true, regions));
|
||||||
|
|
||||||
return TRY(m_open_file_descriptors.read(fd, BAN::ByteSpan(static_cast<uint8_t*>(buffer), count)));
|
return TRY(m_open_file_descriptors.read(fd, BAN::ByteSpan(static_cast<uint8_t*>(buffer), count)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1483,8 +1476,10 @@ namespace Kernel
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, false));
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
BAN::ScopeGuard _([buffer_region] { buffer_region->unpin(); });
|
BAN::ScopeGuard _([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
TRY(validate_and_pin_pointer_access(buffer, count, false, regions));
|
||||||
|
|
||||||
return TRY(m_open_file_descriptors.write(fd, BAN::ConstByteSpan(static_cast<const uint8_t*>(buffer), count)));
|
return TRY(m_open_file_descriptors.write(fd, BAN::ConstByteSpan(static_cast<const uint8_t*>(buffer), count)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1674,8 +1669,9 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
||||||
|
|
||||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, true));
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
BAN::ScopeGuard _([buffer_region] { buffer_region->unpin(); });
|
BAN::ScopeGuard _([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
TRY(validate_and_pin_pointer_access(buffer, count, true, regions));
|
||||||
|
|
||||||
return TRY(inode->read(offset, { reinterpret_cast<uint8_t*>(buffer), count }));
|
return TRY(inode->read(offset, { reinterpret_cast<uint8_t*>(buffer), count }));
|
||||||
}
|
}
|
||||||
@@ -1684,8 +1680,9 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
||||||
|
|
||||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, false));
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
BAN::ScopeGuard _([buffer_region] { buffer_region->unpin(); });
|
BAN::ScopeGuard _([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
TRY(validate_and_pin_pointer_access(buffer, count, false, regions));
|
||||||
|
|
||||||
return TRY(inode->write(offset, { reinterpret_cast<const uint8_t*>(buffer), count })); }
|
return TRY(inode->write(offset, { reinterpret_cast<const uint8_t*>(buffer), count })); }
|
||||||
|
|
||||||
@@ -1705,10 +1702,7 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
if (!m_credentials.is_superuser() && inode->uid() != m_credentials.euid())
|
if (!m_credentials.is_superuser() && inode->uid() != m_credentials.euid())
|
||||||
{
|
|
||||||
dwarnln("cannot chmod uid {} vs {}", inode->uid(), m_credentials.euid());
|
|
||||||
return BAN::Error::from_errno(EPERM);
|
return BAN::Error::from_errno(EPERM);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY(inode->chmod(mode & ~S_IFMASK));
|
TRY(inode->chmod(mode & ~S_IFMASK));
|
||||||
@@ -1880,8 +1874,9 @@ namespace Kernel
|
|||||||
if (!inode->mode().ifsock())
|
if (!inode->mode().ifsock())
|
||||||
return BAN::Error::from_errno(ENOTSOCK);
|
return BAN::Error::from_errno(ENOTSOCK);
|
||||||
|
|
||||||
auto* buffer = TRY(validate_and_pin_pointer_access(user_option_value, option_len, true));
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
BAN::ScopeGuard _([buffer] { buffer->unpin(); });
|
BAN::ScopeGuard _([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
TRY(validate_and_pin_pointer_access(user_option_value, option_len, true, regions));
|
||||||
|
|
||||||
TRY(inode->getsockopt(level, option_name, user_option_value, &option_len));
|
TRY(inode->getsockopt(level, option_name, user_option_value, &option_len));
|
||||||
TRY(write_to_user(user_option_len, &option_len, sizeof(socklen_t)));
|
TRY(write_to_user(user_option_len, &option_len, sizeof(socklen_t)));
|
||||||
@@ -1898,8 +1893,9 @@ namespace Kernel
|
|||||||
if (!inode->mode().ifsock())
|
if (!inode->mode().ifsock())
|
||||||
return BAN::Error::from_errno(ENOTSOCK);
|
return BAN::Error::from_errno(ENOTSOCK);
|
||||||
|
|
||||||
auto* buffer = TRY(validate_and_pin_pointer_access(user_option_value, option_len, false));
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
BAN::ScopeGuard _([buffer] { buffer->unpin(); });
|
BAN::ScopeGuard _([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
TRY(validate_and_pin_pointer_access(user_option_value, option_len, false, regions));
|
||||||
|
|
||||||
TRY(inode->setsockopt(level, option_name, user_option_value, option_len));
|
TRY(inode->setsockopt(level, option_name, user_option_value, option_len));
|
||||||
|
|
||||||
@@ -1913,20 +1909,13 @@ namespace Kernel
|
|||||||
if (flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC))
|
if (flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC))
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
MemoryRegion* address_region1 = nullptr;
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
MemoryRegion* address_region2 = nullptr;
|
BAN::ScopeGuard _([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
|
||||||
BAN::ScopeGuard _([&] {
|
|
||||||
if (address_region1)
|
|
||||||
address_region1->unpin();
|
|
||||||
if (address_region2)
|
|
||||||
address_region2->unpin();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (address_len)
|
if (address_len)
|
||||||
{
|
{
|
||||||
address_region1 = TRY(validate_and_pin_pointer_access(address_len, sizeof(address_len), true));
|
TRY(validate_and_pin_pointer_access(address_len, sizeof(address_len), true, regions));
|
||||||
address_region2 = TRY(validate_and_pin_pointer_access(address, *address_len, true));
|
TRY(validate_and_pin_pointer_access(address, *address_len, true, regions));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto inode = TRY(m_open_file_descriptors.inode_of(socket));
|
auto inode = TRY(m_open_file_descriptors.inode_of(socket));
|
||||||
@@ -1993,23 +1982,17 @@ namespace Kernel
|
|||||||
TRY(read_from_user(user_message, &message, sizeof(msghdr)));
|
TRY(read_from_user(user_message, &message, sizeof(msghdr)));
|
||||||
|
|
||||||
BAN::Vector<MemoryRegion*> regions;
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
TRY(regions.reserve(!!message.msg_name + !!message.msg_control + !!message.msg_iov));
|
BAN::ScopeGuard _([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
|
||||||
BAN::ScopeGuard _([®ions] {
|
|
||||||
for (auto* region : regions)
|
|
||||||
region->unpin();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (message.msg_name)
|
if (message.msg_name)
|
||||||
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_name, message.msg_namelen, true))));
|
TRY(validate_and_pin_pointer_access(message.msg_name, message.msg_namelen, true, regions));
|
||||||
if (message.msg_control)
|
if (message.msg_control)
|
||||||
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_control, message.msg_controllen, true))));
|
TRY(validate_and_pin_pointer_access(message.msg_control, message.msg_controllen, true, regions));
|
||||||
if (message.msg_iov)
|
if (message.msg_iov)
|
||||||
{
|
{
|
||||||
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_iov, message.msg_iovlen * sizeof(iovec), true))));
|
TRY(validate_and_pin_pointer_access(message.msg_iov, message.msg_iovlen * sizeof(iovec), true, regions));
|
||||||
TRY(regions.reserve(regions.size() + message.msg_iovlen));
|
|
||||||
for (int i = 0; i < message.msg_iovlen; i++)
|
for (int i = 0; i < message.msg_iovlen; i++)
|
||||||
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_iov[i].iov_base, message.msg_iov[i].iov_len, true))));
|
TRY(validate_and_pin_pointer_access(message.msg_iov[i].iov_base, message.msg_iov[i].iov_len, true, regions));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto ret = TRY(m_open_file_descriptors.recvmsg(socket, message, flags));
|
const auto ret = TRY(m_open_file_descriptors.recvmsg(socket, message, flags));
|
||||||
@@ -2025,23 +2008,18 @@ namespace Kernel
|
|||||||
TRY(read_from_user(user_message, &message, sizeof(msghdr)));
|
TRY(read_from_user(user_message, &message, sizeof(msghdr)));
|
||||||
|
|
||||||
BAN::Vector<MemoryRegion*> regions;
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
TRY(regions.reserve(!!message.msg_name + !!message.msg_control + !!message.msg_iov));
|
BAN::ScopeGuard _([®ions] { for (auto* region : regions) region->unpin(); });
|
||||||
|
|
||||||
BAN::ScopeGuard _([®ions] {
|
|
||||||
for (auto* region : regions)
|
|
||||||
region->unpin();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (message.msg_name)
|
if (message.msg_name)
|
||||||
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_name, message.msg_namelen, false))));
|
TRY(validate_and_pin_pointer_access(message.msg_name, message.msg_namelen, false, regions));
|
||||||
if (message.msg_control)
|
if (message.msg_control)
|
||||||
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_control, message.msg_controllen, false))));
|
TRY(validate_and_pin_pointer_access(message.msg_control, message.msg_controllen, false, regions));
|
||||||
if (message.msg_iov)
|
if (message.msg_iov)
|
||||||
{
|
{
|
||||||
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_iov, message.msg_iovlen * sizeof(iovec), false))));
|
TRY(validate_and_pin_pointer_access(message.msg_iov, message.msg_iovlen * sizeof(iovec), false, regions));
|
||||||
TRY(regions.reserve(regions.size() + message.msg_iovlen));
|
TRY(regions.reserve(regions.size() + message.msg_iovlen));
|
||||||
for (int i = 0; i < message.msg_iovlen; i++)
|
for (int i = 0; i < message.msg_iovlen; i++)
|
||||||
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_iov[i].iov_base, message.msg_iov[i].iov_len, false))));
|
TRY(validate_and_pin_pointer_access(message.msg_iov[i].iov_base, message.msg_iov[i].iov_len, false, regions));
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRY(m_open_file_descriptors.sendmsg(socket, message, flags));
|
return TRY(m_open_file_descriptors.sendmsg(socket, message, flags));
|
||||||
@@ -2176,8 +2154,9 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_ppoll(pollfd* fds, nfds_t nfds, const timespec* user_timeout, const sigset_t* user_sigmask)
|
BAN::ErrorOr<long> Process::sys_ppoll(pollfd* fds, nfds_t nfds, const timespec* user_timeout, const sigset_t* user_sigmask)
|
||||||
{
|
{
|
||||||
auto* fds_region = TRY(validate_and_pin_pointer_access(fds, nfds * sizeof(pollfd), true));
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
BAN::ScopeGuard _([fds_region] { fds_region->unpin(); });
|
BAN::ScopeGuard _([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
TRY(validate_and_pin_pointer_access(fds, nfds * sizeof(pollfd), true, regions));
|
||||||
|
|
||||||
const auto old_sigmask = Thread::current().m_signal_block_mask;
|
const auto old_sigmask = Thread::current().m_signal_block_mask;
|
||||||
if (user_sigmask != nullptr)
|
if (user_sigmask != nullptr)
|
||||||
@@ -2359,8 +2338,9 @@ namespace Kernel
|
|||||||
timeout.tv_nsec;
|
timeout.tv_nsec;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* events_region = TRY(validate_and_pin_pointer_access(events, maxevents * sizeof(epoll_event), true));
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
BAN::ScopeGuard _([events_region] { events_region->unpin(); });
|
BAN::ScopeGuard _([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
TRY(validate_and_pin_pointer_access(events, maxevents * sizeof(epoll_event), true, regions));
|
||||||
|
|
||||||
const auto old_sigmask = Thread::current().m_signal_block_mask;
|
const auto old_sigmask = Thread::current().m_signal_block_mask;
|
||||||
if (user_sigmask)
|
if (user_sigmask)
|
||||||
@@ -2573,8 +2553,10 @@ namespace Kernel
|
|||||||
if (BAN::Math::will_multiplication_overflow(list_len, sizeof(struct dirent)))
|
if (BAN::Math::will_multiplication_overflow(list_len, sizeof(struct dirent)))
|
||||||
return BAN::Error::from_errno(EOVERFLOW);
|
return BAN::Error::from_errno(EOVERFLOW);
|
||||||
|
|
||||||
auto* list_region = TRY(validate_and_pin_pointer_access(list, list_len * sizeof(struct dirent), true));
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
BAN::ScopeGuard _([list_region] { list_region->unpin(); });
|
BAN::ScopeGuard _([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
TRY(validate_and_pin_pointer_access(list, list_len * sizeof(struct dirent), true, regions));
|
||||||
|
|
||||||
return TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_len));
|
return TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3054,7 +3036,7 @@ namespace Kernel
|
|||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
uint64_t cpu_time_ns { 0 };
|
uint64_t cpu_time_ns { 0 };
|
||||||
for (auto* thread : m_threads)
|
for (auto* thread : m_threads)
|
||||||
cpu_time_ns += thread->cpu_time_ns();
|
cpu_time_ns += thread->cpu_time_total_ns();
|
||||||
tp = {
|
tp = {
|
||||||
.tv_sec = static_cast<time_t>(cpu_time_ns / 1'000'000'000),
|
.tv_sec = static_cast<time_t>(cpu_time_ns / 1'000'000'000),
|
||||||
.tv_nsec = static_cast<long>(cpu_time_ns % 1'000'000'000),
|
.tv_nsec = static_cast<long>(cpu_time_ns % 1'000'000'000),
|
||||||
@@ -3063,7 +3045,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
case CLOCK_THREAD_CPUTIME_ID:
|
case CLOCK_THREAD_CPUTIME_ID:
|
||||||
{
|
{
|
||||||
const auto cpu_time_ns = Thread::current().cpu_time_ns();
|
const auto cpu_time_ns = Thread::current().cpu_time_total_ns();
|
||||||
tp = {
|
tp = {
|
||||||
.tv_sec = static_cast<time_t>(cpu_time_ns / 1'000'000'000),
|
.tv_sec = static_cast<time_t>(cpu_time_ns / 1'000'000'000),
|
||||||
.tv_nsec = static_cast<long>(cpu_time_ns % 1'000'000'000),
|
.tv_nsec = static_cast<long>(cpu_time_ns % 1'000'000'000),
|
||||||
@@ -3411,8 +3393,9 @@ namespace Kernel
|
|||||||
const bool is_private = (op & FUTEX_PRIVATE);
|
const bool is_private = (op & FUTEX_PRIVATE);
|
||||||
op &= ~(FUTEX_PRIVATE | FUTEX_REALTIME);
|
op &= ~(FUTEX_PRIVATE | FUTEX_REALTIME);
|
||||||
|
|
||||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(addr, sizeof(uint32_t), false));
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
BAN::ScopeGuard pin_guard([buffer_region] { buffer_region->unpin(); });
|
BAN::ScopeGuard _0([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
TRY(validate_and_pin_pointer_access(addr, sizeof(uint32_t), false, regions));
|
||||||
|
|
||||||
const paddr_t paddr = m_page_table->physical_address_of(vaddr & PAGE_ADDR_MASK) | (vaddr & ~PAGE_ADDR_MASK);
|
const paddr_t paddr = m_page_table->physical_address_of(vaddr & PAGE_ADDR_MASK) | (vaddr & ~PAGE_ADDR_MASK);
|
||||||
ASSERT(paddr != 0);
|
ASSERT(paddr != 0);
|
||||||
@@ -3473,7 +3456,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LockGuard _(futex->mutex);
|
LockGuard _1(futex->mutex);
|
||||||
|
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
@@ -3556,8 +3539,9 @@ namespace Kernel
|
|||||||
if (stack_vaddr % PAGE_SIZE || stack_size % PAGE_SIZE)
|
if (stack_vaddr % PAGE_SIZE || stack_size % PAGE_SIZE)
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
auto* memory_region = TRY(validate_and_pin_pointer_access(stack_base, stack_size, true));
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
BAN::ScopeGuard _0([memory_region] { if (memory_region) memory_region->unpin(); });
|
BAN::ScopeGuard _0([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
TRY(validate_and_pin_pointer_access(stack_base, stack_size, true, regions));
|
||||||
|
|
||||||
const vaddr_t initial_stack_pointer = stack_vaddr + stack_size - sizeof(void*);
|
const vaddr_t initial_stack_pointer = stack_vaddr + stack_size - sizeof(void*);
|
||||||
*reinterpret_cast<void**>(initial_stack_pointer) = arg;
|
*reinterpret_cast<void**>(initial_stack_pointer) = arg;
|
||||||
@@ -3575,12 +3559,7 @@ namespace Kernel
|
|||||||
LockGuard _1(m_process_lock);
|
LockGuard _1(m_process_lock);
|
||||||
|
|
||||||
TRY(m_threads.push_back(thread));
|
TRY(m_threads.push_back(thread));
|
||||||
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error())
|
Processor::scheduler().add_thread(thread);
|
||||||
{
|
|
||||||
m_threads.pop_back();
|
|
||||||
delete thread;
|
|
||||||
return ret.release_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
return thread->tid();
|
return thread->tid();
|
||||||
}
|
}
|
||||||
@@ -4030,13 +4009,14 @@ namespace Kernel
|
|||||||
if (BAN::Math::will_multiplication_overflow(count, sizeof(gid_t)))
|
if (BAN::Math::will_multiplication_overflow(count, sizeof(gid_t)))
|
||||||
return BAN::Error::from_errno(EOVERFLOW);
|
return BAN::Error::from_errno(EOVERFLOW);
|
||||||
|
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _0(m_process_lock);
|
||||||
|
|
||||||
if (!m_credentials.is_superuser())
|
if (!m_credentials.is_superuser())
|
||||||
return BAN::Error::from_errno(EPERM);
|
return BAN::Error::from_errno(EPERM);
|
||||||
|
|
||||||
auto* region = TRY(validate_and_pin_pointer_access(groups, count * sizeof(gid_t), false));
|
BAN::Vector<MemoryRegion*> regions;
|
||||||
BAN::ScopeGuard pin_guard([region] { region->unpin(); });
|
BAN::ScopeGuard _1([&] { for (auto* region : regions) region->unpin(); });
|
||||||
|
TRY(validate_and_pin_pointer_access(groups, count * sizeof(gid_t), false, regions));
|
||||||
|
|
||||||
TRY(m_credentials.set_groups({ groups, count }));
|
TRY(m_credentials.set_groups({ groups, count }));
|
||||||
|
|
||||||
@@ -4101,26 +4081,23 @@ namespace Kernel
|
|||||||
return region->allocate_page_containing(address, wants_write);
|
return region->allocate_page_containing(address, wants_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<MemoryRegion*> Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write)
|
BAN::ErrorOr<void> Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write, BAN::Vector<MemoryRegion*>& regions)
|
||||||
{
|
{
|
||||||
// TODO: allow pinning multiple regions?
|
vaddr_t vaddr = reinterpret_cast<vaddr_t>(ptr);
|
||||||
|
|
||||||
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(ptr);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
RWLockRDGuard _(m_memory_region_lock);
|
RWLockRDGuard _(m_memory_region_lock);
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr);
|
const size_t first_index = find_mapped_region(vaddr);
|
||||||
for (size_t i = first_index; i < m_mapped_regions.size(); i++)
|
for (size_t i = first_index; i < m_mapped_regions.size(); i++)
|
||||||
{
|
{
|
||||||
auto& region = m_mapped_regions[i];
|
const auto& region = m_mapped_regions[i];
|
||||||
if (user_vaddr >= region->vaddr() + region->size())
|
if (vaddr < region->vaddr())
|
||||||
break;
|
break;
|
||||||
if (!region->contains_fully(user_vaddr, size))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const size_t page_count = range_page_count(user_vaddr, size);
|
const vaddr_t min_vaddr_end = BAN::Math::min(vaddr + size, region->vaddr() + region->size());
|
||||||
const vaddr_t page_base = user_vaddr & PAGE_ADDR_MASK;
|
const size_t page_count = range_page_count(vaddr, min_vaddr_end - vaddr);
|
||||||
|
const vaddr_t page_base = vaddr & PAGE_ADDR_MASK;
|
||||||
for (size_t p = 0; p < page_count; p++)
|
for (size_t p = 0; p < page_count; p++)
|
||||||
{
|
{
|
||||||
const auto flags = PageTable::UserSupervisor | (needs_write ? PageTable::ReadWrite : 0) | PageTable::Present;
|
const auto flags = PageTable::UserSupervisor | (needs_write ? PageTable::ReadWrite : 0) | PageTable::Present;
|
||||||
@@ -4128,8 +4105,15 @@ namespace Kernel
|
|||||||
goto validate_and_pin_pointer_access_with_allocation;
|
goto validate_and_pin_pointer_access_with_allocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRY(regions.push_back(region.ptr()));
|
||||||
region->pin();
|
region->pin();
|
||||||
return region.ptr();
|
|
||||||
|
if (region->contains(vaddr + size - 1))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const vaddr_t next_vaddr = region->vaddr() + region->size();
|
||||||
|
size -= next_vaddr - vaddr;
|
||||||
|
vaddr = next_vaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
@@ -4138,17 +4122,16 @@ namespace Kernel
|
|||||||
validate_and_pin_pointer_access_with_allocation:
|
validate_and_pin_pointer_access_with_allocation:
|
||||||
RWLockWRGuard _(m_memory_region_lock);
|
RWLockWRGuard _(m_memory_region_lock);
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr);
|
const size_t first_index = find_mapped_region(vaddr);
|
||||||
for (size_t i = first_index; i < m_mapped_regions.size(); i++)
|
for (size_t i = first_index; i < m_mapped_regions.size(); i++)
|
||||||
{
|
{
|
||||||
auto& region = m_mapped_regions[i];
|
auto& region = m_mapped_regions[i];
|
||||||
if (user_vaddr >= region->vaddr() + region->size())
|
if (vaddr < region->vaddr())
|
||||||
break;
|
break;
|
||||||
if (!region->contains_fully(user_vaddr, size))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const size_t page_count = range_page_count(user_vaddr, size);
|
const vaddr_t min_vaddr_end = BAN::Math::min(vaddr + size, region->vaddr() + region->size());
|
||||||
const vaddr_t page_base = user_vaddr & PAGE_ADDR_MASK;
|
const size_t page_count = range_page_count(vaddr, min_vaddr_end - vaddr);
|
||||||
|
const vaddr_t page_base = vaddr & PAGE_ADDR_MASK;
|
||||||
for (size_t p = 0; p < page_count; p++)
|
for (size_t p = 0; p < page_count; p++)
|
||||||
{
|
{
|
||||||
const auto flags = PageTable::UserSupervisor | (needs_write ? PageTable::ReadWrite : 0) | PageTable::Present;
|
const auto flags = PageTable::UserSupervisor | (needs_write ? PageTable::ReadWrite : 0) | PageTable::Present;
|
||||||
@@ -4158,8 +4141,15 @@ namespace Kernel
|
|||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRY(regions.push_back(region.ptr()));
|
||||||
region->pin();
|
region->pin();
|
||||||
return region.ptr();
|
|
||||||
|
if (region->contains(vaddr + size - 1))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const vaddr_t next_vaddr = region->vaddr() + region->size();
|
||||||
|
size -= next_vaddr - vaddr;
|
||||||
|
vaddr = next_vaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
#include <kernel/CPUID.h>
|
#include <kernel/CPUID.h>
|
||||||
|
#include <kernel/GDT.h>
|
||||||
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/InterruptController.h>
|
#include <kernel/InterruptController.h>
|
||||||
|
#include <kernel/IO.h>
|
||||||
#include <kernel/Memory/Heap.h>
|
#include <kernel/Memory/Heap.h>
|
||||||
#include <kernel/Memory/kmalloc.h>
|
#include <kernel/Memory/kmalloc.h>
|
||||||
#include <kernel/Processor.h>
|
#include <kernel/Processor.h>
|
||||||
|
#include <kernel/Scheduler.h>
|
||||||
#include <kernel/Terminal/TerminalDriver.h>
|
#include <kernel/Terminal/TerminalDriver.h>
|
||||||
#include <kernel/Thread.h>
|
#include <kernel/Thread.h>
|
||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|||||||
+114
-198
@@ -1,11 +1,11 @@
|
|||||||
#include <BAN/Optional.h>
|
#include <BAN/Optional.h>
|
||||||
#include <BAN/Sort.h>
|
#include <BAN/Sort.h>
|
||||||
#include <kernel/APIC.h>
|
#include <kernel/APIC.h>
|
||||||
|
#include <kernel/GDT.h>
|
||||||
#include <kernel/InterruptController.h>
|
#include <kernel/InterruptController.h>
|
||||||
#include <kernel/Lock/Mutex.h>
|
#include <kernel/Lock/Mutex.h>
|
||||||
#include <kernel/Process.h>
|
#include <kernel/Process.h>
|
||||||
#include <kernel/Scheduler.h>
|
#include <kernel/Scheduler.h>
|
||||||
#include <kernel/SchedulerQueueNode.h>
|
|
||||||
#include <kernel/Thread.h>
|
#include <kernel/Thread.h>
|
||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
@@ -33,88 +33,6 @@ namespace Kernel
|
|||||||
static SpinLock s_processor_info_time_lock;
|
static SpinLock s_processor_info_time_lock;
|
||||||
static BAN::Array<ProcessorInfo, 0xFF> s_processor_infos;
|
static BAN::Array<ProcessorInfo, 0xFF> s_processor_infos;
|
||||||
|
|
||||||
|
|
||||||
static BAN::Atomic<size_t> s_next_processor_index { 0 };
|
|
||||||
|
|
||||||
|
|
||||||
void SchedulerQueue::add_thread_to_back(Node* node)
|
|
||||||
{
|
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
|
||||||
node->next = nullptr;
|
|
||||||
node->prev = m_tail;
|
|
||||||
(m_tail ? m_tail->next : m_head) = node;
|
|
||||||
m_tail = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SchedulerQueue::add_thread_with_wake_time(Node* node)
|
|
||||||
{
|
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
|
||||||
|
|
||||||
if (m_tail == nullptr || node->wake_time_ns >= m_tail->wake_time_ns)
|
|
||||||
{
|
|
||||||
add_thread_to_back(node);
|
|
||||||
return node == m_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node* next = m_head;
|
|
||||||
Node* prev = nullptr;
|
|
||||||
while (next && node->wake_time_ns > next->wake_time_ns)
|
|
||||||
{
|
|
||||||
prev = next;
|
|
||||||
next = next->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->next = next;
|
|
||||||
node->prev = prev;
|
|
||||||
(next ? next->prev : m_tail) = node;
|
|
||||||
(prev ? prev->next : m_head) = node;
|
|
||||||
|
|
||||||
return node == m_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
SchedulerQueue::Node* SchedulerQueue::remove_with_condition(F callback)
|
|
||||||
{
|
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
|
||||||
|
|
||||||
for (Node* node = m_head; node; node = node->next)
|
|
||||||
{
|
|
||||||
if (!callback(node))
|
|
||||||
continue;
|
|
||||||
remove_node(node);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SchedulerQueue::remove_node(Node* node)
|
|
||||||
{
|
|
||||||
(node->prev ? node->prev->next : m_head) = node->next;
|
|
||||||
(node->next ? node->next->prev : m_tail) = node->prev;
|
|
||||||
node->prev = nullptr;
|
|
||||||
node->next = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SchedulerQueue::Node* SchedulerQueue::front()
|
|
||||||
{
|
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
|
||||||
ASSERT(!empty());
|
|
||||||
return m_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
SchedulerQueue::Node* SchedulerQueue::pop_front()
|
|
||||||
{
|
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
|
||||||
if (empty())
|
|
||||||
return nullptr;
|
|
||||||
Node* result = m_head;
|
|
||||||
m_head = m_head->next;
|
|
||||||
(m_head ? m_head->prev : m_tail) = nullptr;
|
|
||||||
result->next = nullptr;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<Scheduler*> Scheduler::create()
|
BAN::ErrorOr<Scheduler*> Scheduler::create()
|
||||||
{
|
{
|
||||||
auto* scheduler = new Scheduler();
|
auto* scheduler = new Scheduler();
|
||||||
@@ -142,7 +60,7 @@ namespace Kernel
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::add_current_to_most_loaded(SchedulerQueue* target_queue)
|
void Scheduler::add_current_to_most_loaded(void* target_list)
|
||||||
{
|
{
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||||
|
|
||||||
@@ -151,7 +69,7 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
if (info.node == m_current)
|
if (info.node == m_current)
|
||||||
{
|
{
|
||||||
info.queue = target_queue;
|
info.list = target_list;
|
||||||
has_current = true;
|
has_current = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -163,8 +81,10 @@ namespace Kernel
|
|||||||
for (; index < m_most_loaded_threads.size() - 1; index++)
|
for (; index < m_most_loaded_threads.size() - 1; index++)
|
||||||
if (m_most_loaded_threads[index].node == nullptr)
|
if (m_most_loaded_threads[index].node == nullptr)
|
||||||
break;
|
break;
|
||||||
m_most_loaded_threads[index].queue = target_queue;
|
m_most_loaded_threads[index] = {
|
||||||
m_most_loaded_threads[index].node = m_current;
|
.list = target_list,
|
||||||
|
.node = m_current,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::sort::sort(m_most_loaded_threads.begin(), m_most_loaded_threads.end(),
|
BAN::sort::sort(m_most_loaded_threads.begin(), m_most_loaded_threads.end(),
|
||||||
@@ -177,7 +97,7 @@ namespace Kernel
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::update_most_loaded_node_queue(SchedulerQueue::Node* node, SchedulerQueue* target_queue)
|
void Scheduler::update_most_loaded_node_list(SchedulerThreadNode* node, void* target_list)
|
||||||
{
|
{
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||||
|
|
||||||
@@ -185,13 +105,13 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
if (info.node == node)
|
if (info.node == node)
|
||||||
{
|
{
|
||||||
info.queue = target_queue;
|
info.list = target_list;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::remove_node_from_most_loaded(SchedulerQueue::Node* node)
|
void Scheduler::remove_node_from_most_loaded(SchedulerThreadNode* node)
|
||||||
{
|
{
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||||
|
|
||||||
@@ -203,8 +123,10 @@ namespace Kernel
|
|||||||
for (; i < m_most_loaded_threads.size() - 1; i++)
|
for (; i < m_most_loaded_threads.size() - 1; i++)
|
||||||
m_most_loaded_threads[i] = m_most_loaded_threads[i + 1];
|
m_most_loaded_threads[i] = m_most_loaded_threads[i + 1];
|
||||||
|
|
||||||
m_most_loaded_threads.back().node = nullptr;
|
m_most_loaded_threads.back() = {
|
||||||
m_most_loaded_threads.back().queue = nullptr;
|
.list = nullptr,
|
||||||
|
.node = nullptr,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::reschedule(YieldRegisters* yield_registers)
|
void Scheduler::reschedule(YieldRegisters* yield_registers)
|
||||||
@@ -212,7 +134,7 @@ namespace Kernel
|
|||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||||
|
|
||||||
// If there are no other threads in run queue, reschedule can be no-op :)
|
// If there are no other threads in run queue, reschedule can be no-op :)
|
||||||
if (m_run_queue.empty() && (!m_current || !m_current->blocked) && current_thread().state() == Thread::State::Executing)
|
if (m_run_list.empty() && (!m_current || !m_current->blocked) && current_thread().state() == Thread::State::Executing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_current == nullptr)
|
if (m_current == nullptr)
|
||||||
@@ -226,18 +148,18 @@ namespace Kernel
|
|||||||
if (&PageTable::current() != &PageTable::kernel())
|
if (&PageTable::current() != &PageTable::kernel())
|
||||||
PageTable::kernel().load();
|
PageTable::kernel().load();
|
||||||
delete m_current->thread;
|
delete m_current->thread;
|
||||||
delete m_current;
|
|
||||||
m_thread_count--;
|
m_thread_count--;
|
||||||
break;
|
break;
|
||||||
case Thread::State::Executing:
|
case Thread::State::Executing:
|
||||||
m_current->thread->yield_registers() = *yield_registers;
|
m_current->thread->yield_registers() = *yield_registers;
|
||||||
m_current->time_used_ns += SystemTimer::get().ns_since_boot() - m_current->last_start_ns;
|
m_current->time_used_ns += SystemTimer::get().ns_since_boot() - m_current->last_start_ns;
|
||||||
add_current_to_most_loaded(m_current->blocked ? &m_block_queue : &m_run_queue);
|
add_current_to_most_loaded(m_current->blocked ? static_cast<void*>(&m_block_list) : &m_run_list);
|
||||||
if (!m_current->blocked)
|
if (!m_current->blocked)
|
||||||
m_run_queue.add_thread_to_back(m_current);
|
m_run_list.push(m_current);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_block_queue.add_thread_with_wake_time(m_current))
|
m_block_list.push(m_current);
|
||||||
|
if (m_block_list.front() == m_current)
|
||||||
update_wake_up_deadline();
|
update_wake_up_deadline();
|
||||||
Processor::set_disable_smp_messages(false);
|
Processor::set_disable_smp_messages(false);
|
||||||
}
|
}
|
||||||
@@ -246,12 +168,12 @@ namespace Kernel
|
|||||||
ASSERT(!m_current->blocked);
|
ASSERT(!m_current->blocked);
|
||||||
m_current->time_used_ns = 0;
|
m_current->time_used_ns = 0;
|
||||||
remove_node_from_most_loaded(m_current);
|
remove_node_from_most_loaded(m_current);
|
||||||
m_run_queue.add_thread_to_back(m_current);
|
m_run_list.push(m_current);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((m_current = m_run_queue.pop_front()))
|
while ((m_current = m_run_list.pop_front()))
|
||||||
{
|
{
|
||||||
if (m_current->thread->state() != Thread::State::Terminated)
|
if (m_current->thread->state() != Thread::State::Terminated)
|
||||||
break;
|
break;
|
||||||
@@ -259,7 +181,6 @@ namespace Kernel
|
|||||||
if (&PageTable::current() != &PageTable::kernel())
|
if (&PageTable::current() != &PageTable::kernel())
|
||||||
PageTable::kernel().load();
|
PageTable::kernel().load();
|
||||||
delete m_current->thread;
|
delete m_current->thread;
|
||||||
delete m_current;
|
|
||||||
m_thread_count--;
|
m_thread_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +194,7 @@ namespace Kernel
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_most_loaded_node_queue(m_current, nullptr);
|
update_most_loaded_node_list(m_current, nullptr);
|
||||||
|
|
||||||
auto* thread = m_current->thread;
|
auto* thread = m_current->thread;
|
||||||
|
|
||||||
@@ -309,8 +230,8 @@ namespace Kernel
|
|||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||||
|
|
||||||
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
||||||
while (!m_block_queue.empty() && current_ns >= m_block_queue.front()->wake_time_ns)
|
while (!m_block_list.empty() && current_ns >= m_block_list.front()->wake_time_ns)
|
||||||
unblock_thread(m_block_queue.front());
|
unblock_thread(m_block_list.front()->thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::update_wake_up_deadline()
|
void Scheduler::update_wake_up_deadline()
|
||||||
@@ -324,8 +245,8 @@ namespace Kernel
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
uint64_t deadline_ns = m_next_reschedule_ns;
|
uint64_t deadline_ns = m_next_reschedule_ns;
|
||||||
if (!m_block_queue.empty())
|
if (!m_block_list.empty())
|
||||||
deadline_ns = BAN::Math::min(deadline_ns, m_block_queue.front()->wake_time_ns);
|
deadline_ns = BAN::Math::min(deadline_ns, m_block_list.front()->wake_time_ns);
|
||||||
if (Processor::is_smp_enabled())
|
if (Processor::is_smp_enabled())
|
||||||
deadline_ns = BAN::Math::min(deadline_ns, m_last_load_balance_ns + s_load_balance_interval_ns);
|
deadline_ns = BAN::Math::min(deadline_ns, m_last_load_balance_ns + s_load_balance_interval_ns);
|
||||||
|
|
||||||
@@ -336,7 +257,7 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||||
|
|
||||||
if ((is_idle() && !m_run_queue.empty()) || m_has_pending_reschedule)
|
if ((is_idle() && !m_run_list.empty()) || m_has_pending_reschedule)
|
||||||
{
|
{
|
||||||
m_has_pending_reschedule = false;
|
m_has_pending_reschedule = false;
|
||||||
Processor::yield();
|
Processor::yield();
|
||||||
@@ -374,56 +295,6 @@ namespace Kernel
|
|||||||
update_wake_up_deadline();
|
update_wake_up_deadline();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::unblock_thread(SchedulerQueue::Node* node)
|
|
||||||
{
|
|
||||||
auto state = Processor::get_interrupt_state();
|
|
||||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
|
||||||
|
|
||||||
if (node->processor_id == Processor::current_id())
|
|
||||||
{
|
|
||||||
if (!node->blocked)
|
|
||||||
return;
|
|
||||||
ASSERT(node != m_current);
|
|
||||||
Processor::set_disable_smp_messages(true);
|
|
||||||
m_block_queue.remove_node(node);
|
|
||||||
if (auto* blocker = node->blocker.load())
|
|
||||||
blocker->remove_thread_from_block_queue(node);
|
|
||||||
node->blocked = false;
|
|
||||||
m_run_queue.add_thread_to_back(node);
|
|
||||||
update_most_loaded_node_queue(node, &m_run_queue);
|
|
||||||
Processor::set_disable_smp_messages(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Processor::send_smp_message(node->processor_id, {
|
|
||||||
.type = Processor::SMPMessage::Type::UnblockThread,
|
|
||||||
.unblock_thread = node
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Processor::set_interrupt_state(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scheduler::add_thread(SchedulerQueue::Node* node)
|
|
||||||
{
|
|
||||||
auto state = Processor::get_interrupt_state();
|
|
||||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
|
||||||
|
|
||||||
ASSERT(node->processor_id == Processor::current_id());
|
|
||||||
|
|
||||||
if (!node->blocked)
|
|
||||||
m_run_queue.add_thread_to_back(node);
|
|
||||||
else if (m_block_queue.add_thread_with_wake_time(node))
|
|
||||||
update_wake_up_deadline();
|
|
||||||
|
|
||||||
if (auto* thread = node->thread; thread->is_userspace() && thread->has_process())
|
|
||||||
thread->update_processor_index_address();
|
|
||||||
|
|
||||||
m_thread_count++;
|
|
||||||
|
|
||||||
Processor::set_interrupt_state(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessorID Scheduler::find_least_loaded_processor() const
|
ProcessorID Scheduler::find_least_loaded_processor() const
|
||||||
{
|
{
|
||||||
ProcessorID least_loaded_id = Processor::current_id();
|
ProcessorID least_loaded_id = Processor::current_id();
|
||||||
@@ -482,21 +353,21 @@ namespace Kernel
|
|||||||
const uint64_t load_percent_x1000 = BAN::Math::div_round_up<uint64_t>(m_current->time_used_ns * 100'000, processing_ns);
|
const uint64_t load_percent_x1000 = BAN::Math::div_round_up<uint64_t>(m_current->time_used_ns * 100'000, processing_ns);
|
||||||
dprintln(" tid { 2}: { 3}.{3}% <{}> current", m_current->thread->tid(), load_percent_x1000 / 1000, load_percent_x1000 % 1000, name);
|
dprintln(" tid { 2}: { 3}.{3}% <{}> current", m_current->thread->tid(), load_percent_x1000 / 1000, load_percent_x1000 % 1000, name);
|
||||||
}
|
}
|
||||||
m_run_queue.remove_with_condition(
|
m_run_list.walk(
|
||||||
[&](SchedulerQueue::Node* node)
|
[](const SchedulerThreadNode* node, void* arg)
|
||||||
{
|
{
|
||||||
|
const uint64_t processing_ns = *static_cast<const uint64_t*>(arg);
|
||||||
const uint64_t load_percent_x1000 = BAN::Math::div_round_up<uint64_t>(node->time_used_ns * 100'000, processing_ns);
|
const uint64_t load_percent_x1000 = BAN::Math::div_round_up<uint64_t>(node->time_used_ns * 100'000, processing_ns);
|
||||||
dprintln(" tid { 2}: { 3}.{3}% active", node->thread->tid(), load_percent_x1000 / 1000, load_percent_x1000 % 1000);
|
dprintln(" tid { 2}: { 3}.{3}% active", node->thread->tid(), load_percent_x1000 / 1000, load_percent_x1000 % 1000);
|
||||||
return false;
|
}, const_cast<uint64_t*>(&processing_ns)
|
||||||
}
|
|
||||||
);
|
);
|
||||||
m_block_queue.remove_with_condition(
|
m_block_list.walk(
|
||||||
[&](SchedulerQueue::Node* node)
|
[](const SchedulerThreadNode* node, void* arg)
|
||||||
{
|
{
|
||||||
|
const uint64_t processing_ns = *static_cast<const uint64_t*>(arg);
|
||||||
const uint64_t load_percent_x1000 = BAN::Math::div_round_up<uint64_t>(node->time_used_ns * 100'000, processing_ns);
|
const uint64_t load_percent_x1000 = BAN::Math::div_round_up<uint64_t>(node->time_used_ns * 100'000, processing_ns);
|
||||||
dprintln(" tid { 2}: { 3}.{3}% blocked", node->thread->tid(), load_percent_x1000 / 1000, load_percent_x1000 % 1000);
|
dprintln(" tid { 2}: { 3}.{3}% blocked", node->thread->tid(), load_percent_x1000 / 1000, load_percent_x1000 % 1000);
|
||||||
return false;
|
}, const_cast<uint64_t*>(&processing_ns)
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,7 +403,7 @@ namespace Kernel
|
|||||||
auto& thread_info = m_most_loaded_threads[i];
|
auto& thread_info = m_most_loaded_threads[i];
|
||||||
if (thread_info.node == nullptr)
|
if (thread_info.node == nullptr)
|
||||||
break;
|
break;
|
||||||
if (thread_info.node == m_current || thread_info.queue == nullptr)
|
if (thread_info.node == m_current || thread_info.list == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto least_loaded_id = find_least_loaded_processor();
|
auto least_loaded_id = find_least_loaded_processor();
|
||||||
@@ -596,20 +467,22 @@ namespace Kernel
|
|||||||
|
|
||||||
thread_info.node->time_used_ns = 0;
|
thread_info.node->time_used_ns = 0;
|
||||||
|
|
||||||
{
|
if (thread_info.list == &m_run_list)
|
||||||
auto& my_queue = (thread_info.queue == &m_run_queue) ? m_run_queue : m_block_queue;
|
m_run_list.pop(thread_info.node);
|
||||||
my_queue.remove_node(thread_info.node);
|
else
|
||||||
m_thread_count--;
|
m_block_list.pop(thread_info.node);
|
||||||
}
|
m_thread_count--;
|
||||||
|
|
||||||
thread_info.node->processor_id = least_loaded_id;
|
thread_info.node->processor_id = least_loaded_id;
|
||||||
Processor::send_smp_message(least_loaded_id, {
|
Processor::send_smp_message(least_loaded_id, {
|
||||||
.type = Processor::SMPMessage::Type::NewThread,
|
.type = Processor::SMPMessage::Type::NewThread,
|
||||||
.new_thread = thread_info.node
|
.new_thread = thread_info.node->thread
|
||||||
});
|
});
|
||||||
|
|
||||||
thread_info.node = nullptr;
|
thread_info = {
|
||||||
thread_info.queue = nullptr;
|
.list = nullptr,
|
||||||
|
.node = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
if (m_idle_ns == 0)
|
if (m_idle_ns == 0)
|
||||||
break;
|
break;
|
||||||
@@ -622,8 +495,8 @@ namespace Kernel
|
|||||||
m_current->time_used_ns = 0;
|
m_current->time_used_ns = 0;
|
||||||
for (auto& thread_info : m_most_loaded_threads)
|
for (auto& thread_info : m_most_loaded_threads)
|
||||||
thread_info = {};
|
thread_info = {};
|
||||||
m_run_queue .remove_with_condition([&](SchedulerQueue::Node* node) { node->time_used_ns = 0; return false; });
|
m_run_list .walk([](const SchedulerThreadNode* node, void*) { const_cast<SchedulerThreadNode*>(node)->time_used_ns = 0; }, nullptr);
|
||||||
m_block_queue.remove_with_condition([&](SchedulerQueue::Node* node) { node->time_used_ns = 0; return false; });
|
m_block_list.walk([](const SchedulerThreadNode* node, void*) { const_cast<SchedulerThreadNode*>(node)->time_used_ns = 0; }, nullptr);
|
||||||
m_idle_ns = 0;
|
m_idle_ns = 0;
|
||||||
|
|
||||||
m_should_calculate_max_load_threads = true;
|
m_should_calculate_max_load_threads = true;
|
||||||
@@ -631,41 +504,52 @@ namespace Kernel
|
|||||||
m_last_load_balance_ns += s_load_balance_interval_ns;
|
m_last_load_balance_ns += s_load_balance_interval_ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Scheduler::bind_thread_to_processor(Thread* thread, ProcessorID processor_id)
|
void Scheduler::bind_thread_to_processor(Thread* thread, ProcessorID processor_id)
|
||||||
{
|
{
|
||||||
ASSERT(thread->m_scheduler_node == nullptr);
|
|
||||||
auto* new_node = new SchedulerQueue::Node(thread);
|
|
||||||
if (new_node == nullptr)
|
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
|
|
||||||
ASSERT(processor_id != PROCESSOR_NONE);
|
ASSERT(processor_id != PROCESSOR_NONE);
|
||||||
new_node->processor_id = processor_id;
|
ASSERT(thread->m_scheduler_node.processor_id == PROCESSOR_NONE);
|
||||||
thread->m_scheduler_node = new_node;
|
thread->m_scheduler_node.processor_id = processor_id;
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Scheduler::add_thread(Thread* thread)
|
void Scheduler::add_thread(Thread* thread)
|
||||||
{
|
{
|
||||||
if (thread->m_scheduler_node == nullptr)
|
ASSERT(thread);
|
||||||
|
|
||||||
|
if (thread->m_scheduler_node.processor_id == PROCESSOR_NONE)
|
||||||
{
|
{
|
||||||
|
static BAN::Atomic<size_t> s_next_processor_index { 0 };
|
||||||
const size_t processor_index = s_next_processor_index++ % Processor::count();
|
const size_t processor_index = s_next_processor_index++ % Processor::count();
|
||||||
const auto processor_id = Processor::id_from_index(processor_index);
|
const auto processor_id = Processor::id_from_index(processor_index);
|
||||||
TRY(bind_thread_to_processor(thread, processor_id));
|
bind_thread_to_processor(thread, processor_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* node = thread->m_scheduler_node;
|
if (const auto proc_id = thread->m_scheduler_node.processor_id; proc_id != Processor::current_id())
|
||||||
if (node->processor_id == Processor::current_id())
|
{
|
||||||
add_thread(node);
|
Processor::send_smp_message(proc_id, {
|
||||||
|
.type = Processor::SMPMessage::Type::NewThread,
|
||||||
|
.new_thread = thread
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto state = Processor::get_interrupt_state();
|
||||||
|
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||||
|
|
||||||
|
if (!thread->m_scheduler_node.blocked)
|
||||||
|
m_run_list.push(&thread->m_scheduler_node);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Processor::send_smp_message(node->processor_id, {
|
m_block_list.push(&thread->m_scheduler_node);
|
||||||
.type = Processor::SMPMessage::Type::NewThread,
|
if (m_block_list.front() == &thread->m_scheduler_node)
|
||||||
.new_thread = node
|
update_wake_up_deadline();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
if (thread->is_userspace() && thread->has_process())
|
||||||
|
thread->update_processor_index_address();
|
||||||
|
|
||||||
|
m_thread_count++;
|
||||||
|
|
||||||
|
Processor::set_interrupt_state(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::block_current_thread(ThreadBlocker* blocker, uint64_t wake_time_ns, BaseMutex* mutex)
|
void Scheduler::block_current_thread(ThreadBlocker* blocker, uint64_t wake_time_ns, BaseMutex* mutex)
|
||||||
@@ -673,7 +557,7 @@ namespace Kernel
|
|||||||
if (SystemTimer::get().ns_since_boot() >= wake_time_ns)
|
if (SystemTimer::get().ns_since_boot() >= wake_time_ns)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto state = Processor::get_interrupt_state();
|
const auto state = Processor::get_interrupt_state();
|
||||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||||
|
|
||||||
ASSERT(m_current->processor_id == Processor::current_id());
|
ASSERT(m_current->processor_id == Processor::current_id());
|
||||||
@@ -707,7 +591,39 @@ namespace Kernel
|
|||||||
|
|
||||||
void Scheduler::unblock_thread(Thread* thread)
|
void Scheduler::unblock_thread(Thread* thread)
|
||||||
{
|
{
|
||||||
unblock_thread(thread->m_scheduler_node);
|
if (const auto proc_id = thread->m_scheduler_node.processor_id; proc_id != Processor::current_id())
|
||||||
|
{
|
||||||
|
Processor::send_smp_message(proc_id, {
|
||||||
|
.type = Processor::SMPMessage::Type::UnblockThread,
|
||||||
|
.unblock_thread = thread
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto state = Processor::get_interrupt_state();
|
||||||
|
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||||
|
|
||||||
|
if (!thread->m_scheduler_node.blocked)
|
||||||
|
{
|
||||||
|
Processor::set_interrupt_state(state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(&thread->m_scheduler_node != m_current);
|
||||||
|
|
||||||
|
Processor::set_disable_smp_messages(true);
|
||||||
|
|
||||||
|
m_block_list.pop(&thread->m_scheduler_node);
|
||||||
|
if (auto* blocker = thread->m_scheduler_node.blocker.load())
|
||||||
|
blocker->remove_thread_from_block_queue(&thread->m_scheduler_node);
|
||||||
|
thread->m_scheduler_node.blocked = false;
|
||||||
|
|
||||||
|
m_run_list.push(&thread->m_scheduler_node);
|
||||||
|
update_most_loaded_node_list(&thread->m_scheduler_node, &m_run_list);
|
||||||
|
|
||||||
|
Processor::set_disable_smp_messages(false);
|
||||||
|
|
||||||
|
Processor::set_interrupt_state(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread& Scheduler::current_thread()
|
Thread& Scheduler::current_thread()
|
||||||
|
|||||||
@@ -0,0 +1,266 @@
|
|||||||
|
#include <BAN/Assert.h>
|
||||||
|
#include <BAN/Swap.h>
|
||||||
|
#include <kernel/SchedulerThreadNode.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
SchedulerThreadNode* SchedulerQueue::front()
|
||||||
|
{
|
||||||
|
return m_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
SchedulerThreadNode* SchedulerQueue::pop_front()
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
return nullptr;
|
||||||
|
auto* const result = m_head;
|
||||||
|
m_head = m_head->queue.next;
|
||||||
|
(m_head ? m_head->queue.prev : m_tail) = nullptr;
|
||||||
|
result->queue.prev = nullptr;
|
||||||
|
result->queue.next = nullptr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SchedulerQueue::push(SchedulerThreadNode* node)
|
||||||
|
{
|
||||||
|
ASSERT(node->queue.prev == nullptr);
|
||||||
|
ASSERT(node->queue.next == nullptr);
|
||||||
|
|
||||||
|
node->queue.prev = m_tail;
|
||||||
|
node->queue.next = nullptr;
|
||||||
|
(m_tail ? m_tail->queue.next : m_head) = node;
|
||||||
|
m_tail = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SchedulerQueue::pop(SchedulerThreadNode* node)
|
||||||
|
{
|
||||||
|
(node->queue.prev ? node->queue.prev->queue.next : m_head) = node->queue.next;
|
||||||
|
(node->queue.next ? node->queue.next->queue.prev : m_tail) = node->queue.prev;
|
||||||
|
node->queue.prev = nullptr;
|
||||||
|
node->queue.next = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SchedulerQueue::walk(void (*callback)(const SchedulerThreadNode*, void*), void* arg) const
|
||||||
|
{
|
||||||
|
for (auto* node = m_head; node; node = node->queue.next)
|
||||||
|
callback(node, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SchedulerThreadNode* SchedulerHeap::front()
|
||||||
|
{
|
||||||
|
return m_root;
|
||||||
|
}
|
||||||
|
|
||||||
|
SchedulerThreadNode* SchedulerHeap::pop_front()
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
return nullptr;
|
||||||
|
auto* const result = m_root;
|
||||||
|
pop(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SchedulerHeap::push(SchedulerThreadNode* node)
|
||||||
|
{
|
||||||
|
ASSERT(node->heap.parent == nullptr);
|
||||||
|
ASSERT(node->heap.lchild == nullptr);
|
||||||
|
ASSERT(node->heap.rchild == nullptr);
|
||||||
|
|
||||||
|
if (m_root == nullptr)
|
||||||
|
{
|
||||||
|
// push to empty heap
|
||||||
|
node->heap.parent = nullptr;
|
||||||
|
node->heap.lchild = nullptr;
|
||||||
|
node->heap.rchild = nullptr;
|
||||||
|
m_root = node;
|
||||||
|
m_last = node;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* parent = m_last;
|
||||||
|
|
||||||
|
{
|
||||||
|
// find parent of the new node
|
||||||
|
SchedulerThreadNode* temp;
|
||||||
|
while ((temp = parent->heap.parent) && parent == temp->heap.rchild)
|
||||||
|
parent = temp;
|
||||||
|
if (temp && temp->heap.rchild == nullptr)
|
||||||
|
parent = temp;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (temp != nullptr)
|
||||||
|
parent = temp->heap.rchild;
|
||||||
|
while ((temp = parent->heap.lchild))
|
||||||
|
parent = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert node as the last node
|
||||||
|
(parent->heap.lchild ? parent->heap.rchild : parent->heap.lchild) = node;
|
||||||
|
node->heap.parent = parent;
|
||||||
|
node->heap.lchild = nullptr;
|
||||||
|
node->heap.rchild = nullptr;
|
||||||
|
m_last = node;
|
||||||
|
|
||||||
|
// fix heap properties
|
||||||
|
while ((parent = node->heap.parent) && node->wake_time_ns < parent->wake_time_ns)
|
||||||
|
swap_nodes(node, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SchedulerHeap::pop(SchedulerThreadNode* old_node)
|
||||||
|
{
|
||||||
|
if (m_root == m_last)
|
||||||
|
{
|
||||||
|
// remove the only node
|
||||||
|
old_node->heap.parent = nullptr;
|
||||||
|
old_node->heap.lchild = nullptr;
|
||||||
|
old_node->heap.rchild = nullptr;
|
||||||
|
m_root = nullptr;
|
||||||
|
m_last = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* fix_node = m_last;
|
||||||
|
swap_nodes(old_node, m_last);
|
||||||
|
|
||||||
|
{
|
||||||
|
// update last to point to the previous node
|
||||||
|
SchedulerThreadNode* temp;
|
||||||
|
while ((temp = m_last->heap.parent) && m_last == temp->heap.lchild)
|
||||||
|
m_last = temp;
|
||||||
|
if (temp != nullptr)
|
||||||
|
m_last = temp->heap.lchild;
|
||||||
|
ASSERT(m_last);
|
||||||
|
while ((temp = m_last->heap.rchild))
|
||||||
|
m_last = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// delete links to/from the deleted node
|
||||||
|
if (auto* parent = old_node->heap.parent)
|
||||||
|
(old_node == parent->heap.rchild ? parent->heap.rchild : parent->heap.lchild) = nullptr;
|
||||||
|
old_node->heap.parent = nullptr;
|
||||||
|
old_node->heap.lchild = nullptr;
|
||||||
|
old_node->heap.rchild = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix heap properties
|
||||||
|
if (fix_node->wake_time_ns == old_node->wake_time_ns)
|
||||||
|
;
|
||||||
|
else if (fix_node->wake_time_ns < old_node->wake_time_ns)
|
||||||
|
{
|
||||||
|
SchedulerThreadNode* parent;
|
||||||
|
while ((parent = fix_node->heap.parent) && fix_node->wake_time_ns < parent->wake_time_ns)
|
||||||
|
swap_nodes(fix_node, parent);
|
||||||
|
}
|
||||||
|
else for (;;)
|
||||||
|
{
|
||||||
|
const bool l_ok = !fix_node->heap.lchild || fix_node->wake_time_ns <= fix_node->heap.lchild->wake_time_ns;
|
||||||
|
const bool r_ok = !fix_node->heap.rchild || fix_node->wake_time_ns <= fix_node->heap.rchild->wake_time_ns;
|
||||||
|
if (l_ok && r_ok)
|
||||||
|
break;
|
||||||
|
auto* child = (!l_ok && !r_ok)
|
||||||
|
? (fix_node->heap.lchild->wake_time_ns < fix_node->heap.rchild->wake_time_ns ? fix_node->heap.lchild : fix_node->heap.rchild)
|
||||||
|
: (r_ok ? fix_node->heap.lchild : fix_node->heap.rchild);
|
||||||
|
swap_nodes(fix_node, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SchedulerHeap::walk(void (*callback)(const SchedulerThreadNode*, void*), void* arg) const
|
||||||
|
{
|
||||||
|
walk_impl(callback, arg, m_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SchedulerHeap::walk_impl(void (*callback)(const SchedulerThreadNode*, void*), void* arg, const SchedulerThreadNode* node) const
|
||||||
|
{
|
||||||
|
if (node == nullptr)
|
||||||
|
return;
|
||||||
|
callback(node, arg);
|
||||||
|
walk_impl(callback, arg, node->heap.lchild);
|
||||||
|
walk_impl(callback, arg, node->heap.rchild);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SchedulerHeap::swap_nodes(SchedulerThreadNode* node1, SchedulerThreadNode* node2)
|
||||||
|
{
|
||||||
|
if (node1 == node2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (node2 == node1->heap.parent)
|
||||||
|
BAN::swap(node1, node2);
|
||||||
|
|
||||||
|
auto* const p1 = node1->heap.parent;
|
||||||
|
auto* const l1 = node1->heap.lchild;
|
||||||
|
auto* const r1 = node1->heap.rchild;
|
||||||
|
|
||||||
|
auto* const p2 = node2->heap.parent;
|
||||||
|
auto* const l2 = node2->heap.lchild;
|
||||||
|
auto* const r2 = node2->heap.rchild;
|
||||||
|
|
||||||
|
if (node1 == node2->heap.parent)
|
||||||
|
{
|
||||||
|
node1->heap.parent = node2;
|
||||||
|
node1->heap.lchild = l2;
|
||||||
|
node1->heap.rchild = r2;
|
||||||
|
|
||||||
|
node2->heap.parent = p1;
|
||||||
|
|
||||||
|
if (l1 == node2)
|
||||||
|
{
|
||||||
|
node2->heap.lchild = node1;
|
||||||
|
node2->heap.rchild = r1;
|
||||||
|
if (r1) r1->heap.parent = node2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node2->heap.lchild = l1;
|
||||||
|
node2->heap.rchild = node1;
|
||||||
|
if (l1) l1->heap.parent = node2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p1) (node1 == p1->heap.lchild ? p1->heap.lchild : p1->heap.rchild) = node2;
|
||||||
|
|
||||||
|
if (l2) l2->heap.parent = node1;
|
||||||
|
if (r2) r2->heap.parent = node1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node1->heap.parent = p2;
|
||||||
|
node1->heap.lchild = l2;
|
||||||
|
node1->heap.rchild = r2;
|
||||||
|
|
||||||
|
node2->heap.parent = p1;
|
||||||
|
node2->heap.lchild = l1;
|
||||||
|
node2->heap.rchild = r1;
|
||||||
|
|
||||||
|
if (l1) l1->heap.parent = node2;
|
||||||
|
if (r1) r1->heap.parent = node2;
|
||||||
|
|
||||||
|
if (l2) l2->heap.parent = node1;
|
||||||
|
if (r2) r2->heap.parent = node1;
|
||||||
|
|
||||||
|
if (p1 || p2)
|
||||||
|
{
|
||||||
|
if (p1 == p2)
|
||||||
|
BAN::swap(p1->heap.lchild, p1->heap.rchild);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (p1) (p1->heap.lchild == node1 ? p1->heap.lchild : p1->heap.rchild) = node2;
|
||||||
|
if (p2) (p2->heap.lchild == node2 ? p2->heap.lchild : p2->heap.rchild) = node1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* const root = m_root;
|
||||||
|
auto* const last = m_last;
|
||||||
|
|
||||||
|
if (node1 == root) m_root = node2;
|
||||||
|
else if (node1 == last) m_last = node2;
|
||||||
|
|
||||||
|
if (node2 == root) m_root = node1;
|
||||||
|
else if (node2 == last) m_last = node1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -94,7 +94,7 @@ namespace Kernel
|
|||||||
|
|
||||||
while (is != 0)
|
while (is != 0)
|
||||||
{
|
{
|
||||||
const size_t idx = __builtin_ctz(is);
|
const size_t idx = BAN::Math::ctz(is);
|
||||||
if (auto& device = m_devices[idx])
|
if (auto& device = m_devices[idx])
|
||||||
device->handle_irq();
|
device->handle_irq();
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <kernel/Lock/BlockableSpinLock.h>
|
||||||
#include <kernel/Lock/LockGuard.h>
|
#include <kernel/Lock/LockGuard.h>
|
||||||
#include <kernel/Scheduler.h>
|
#include <kernel/Scheduler.h>
|
||||||
#include <kernel/Storage/ATA/AHCI/Controller.h>
|
#include <kernel/Storage/ATA/AHCI/Controller.h>
|
||||||
@@ -301,7 +302,7 @@ namespace Kernel
|
|||||||
const vaddr_t buffer_vaddr = reinterpret_cast<vaddr_t>(buffer.data());
|
const vaddr_t buffer_vaddr = reinterpret_cast<vaddr_t>(buffer.data());
|
||||||
const paddr_t buffer_paddr = to_paddr(buffer_vaddr);
|
const paddr_t buffer_paddr = to_paddr(buffer_vaddr);
|
||||||
|
|
||||||
const size_t bytes = BAN::Math::min(buffer.size(), PAGE_SIZE - buffer_vaddr % PAGE_SIZE);
|
const size_t bytes = BAN::Math::min<size_t>(buffer.size(), PAGE_SIZE - buffer_vaddr % PAGE_SIZE);
|
||||||
|
|
||||||
bool can_extend = true;
|
bool can_extend = true;
|
||||||
if (prdt_count == 0)
|
if (prdt_count == 0)
|
||||||
@@ -424,7 +425,7 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
if (const uint32_t usable_slots = ~(m_port->sact | m_port->ci) & m_free_slots)
|
if (const uint32_t usable_slots = ~(m_port->sact | m_port->ci) & m_free_slots)
|
||||||
{
|
{
|
||||||
const uint32_t slot = __builtin_ctz(usable_slots);
|
const uint32_t slot = BAN::Math::ctz(usable_slots);
|
||||||
m_free_slots &= ~(1u << slot);
|
m_free_slots &= ~(1u << slot);
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user