Compare commits
105 Commits
689494db63
...
49662aa994
| Author | SHA1 | Date | |
|---|---|---|---|
| 49662aa994 | |||
| bcf1c6d110 | |||
| b62687f5e7 | |||
| 7b4b5a3440 | |||
| 896bb05073 | |||
| fc10de7ccb | |||
| e8a490336c | |||
| e741ab0fa1 | |||
| 7d7b1f0319 | |||
| 97d26b5d4e | |||
| e78fcf63b6 | |||
| bfad22211f | |||
| 6e2542d896 | |||
| 659bc50aec | |||
| f6c5e3e640 | |||
| 8957408890 | |||
| db8544065e | |||
| eee0b7c3ff | |||
| ea4e016b1e | |||
| 9fd015a84e | |||
| 090ab99903 | |||
| 3e16e69602 | |||
| 58c58bcccf | |||
| f173b7bccc | |||
| fde0eb0964 | |||
| 05ee0a7f49 | |||
| a863b2ca13 | |||
| 15f6158cea | |||
| c7eb2dbdf3 | |||
| 380b172968 | |||
| ae0e79aa01 | |||
| 01f0871a83 | |||
| ac1fafedcc | |||
| 7a696c4d63 | |||
| 89d3ee7b92 | |||
| 879783052d | |||
| b480f783ec | |||
| 2957206718 | |||
| a41a3eeb66 | |||
| 6aa2329267 | |||
| 5256fd2e0a | |||
| 652e170da9 | |||
| a2691bd70d | |||
| b2169cbce6 | |||
| c9b3d50523 | |||
| e717b95df0 | |||
| 0d8d731d91 | |||
| 122c325a5b | |||
| d5bc88584d | |||
| 63b2284324 | |||
| 917321eb5f | |||
| 13bf1ba647 | |||
| 0a8b03d349 | |||
| 4473ee4d49 | |||
| ded722fb4c | |||
| facc17c5a1 | |||
| 26abd4e18e | |||
| 50fd526e6f | |||
| c0e091b647 | |||
| 372da006d0 | |||
| 7219eac65f | |||
| 0dc74beb0f | |||
| 7bdd9d19d0 | |||
| 991f7024d5 | |||
| 6d1696b77e | |||
| b19b7f064a | |||
| f449ca8161 | |||
| 5540bc4147 | |||
| d8f136a76f | |||
| 8be90c49bc | |||
| 59c59c3316 | |||
| c5cfa82ffb | |||
| c0d38862f2 | |||
| 74e94eedae | |||
| d241975ce1 | |||
| 20663b533b | |||
| 6f002f0c07 | |||
| f121e80bfd | |||
| 4e28a35af9 | |||
| ddb7641b05 | |||
| a6ad9b9b2e | |||
| c0bd07174d | |||
| 8f4e15b78e | |||
| 17e6e53948 | |||
| 223835c37d | |||
| aedd53b3e0 | |||
| 6339044e4c | |||
| 924576cf0d | |||
| ac333c9677 | |||
| 6e47fa084b | |||
| 32c10f7db2 | |||
| 9919cbf66e | |||
| fc1a6cacdc | |||
| 040bdea08e | |||
| 579cd07109 | |||
| 7bf7de44d2 | |||
| 58aff97c28 | |||
| 2bb9b9b4b3 | |||
| 59ec05c898 | |||
| ac0ef53e87 | |||
| 5aea95129e | |||
| 92d10f612e | |||
| f3f40a465b | |||
| d3130884b6 | |||
| 5a516a6130 |
@@ -67,11 +67,20 @@ namespace BAN::sort
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void quick_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
if (distance(begin, end) <= 1)
|
||||
return;
|
||||
const auto [lt, gt] = detail::partition(begin, end, comp);
|
||||
quick_sort(begin, lt, comp);
|
||||
quick_sort(gt, end, comp);
|
||||
while (distance(begin, end) > 1)
|
||||
{
|
||||
const auto [lt, gt] = detail::partition(begin, end, comp);
|
||||
if (distance(begin, lt) < distance(gt, end))
|
||||
{
|
||||
quick_sort(begin, lt);
|
||||
begin = gt;
|
||||
}
|
||||
else
|
||||
{
|
||||
quick_sort(gt, end);
|
||||
end = lt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
@@ -102,13 +111,28 @@ namespace BAN::sort
|
||||
template<typename It, typename Comp>
|
||||
void intro_sort_impl(It begin, It end, size_t max_depth, Comp comp)
|
||||
{
|
||||
if (distance(begin, end) <= 16)
|
||||
return insertion_sort(begin, end, comp);
|
||||
if (max_depth == 0)
|
||||
return heap_sort(begin, end, comp);
|
||||
const auto [lt, gt] = detail::partition(begin, end, comp);
|
||||
intro_sort_impl(begin, lt, max_depth - 1, comp);
|
||||
intro_sort_impl(gt, end, max_depth - 1, comp);
|
||||
for (size_t i = 0; i < max_depth; i++)
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
if (len <= 1)
|
||||
return;
|
||||
if (len <= 16)
|
||||
return insertion_sort(begin, end, comp);
|
||||
|
||||
const auto [lt, gt] = detail::partition(begin, end, comp);
|
||||
if (distance(begin, lt) < distance(gt, end))
|
||||
{
|
||||
intro_sort_impl(begin, lt, max_depth - 1, comp);
|
||||
begin = gt;
|
||||
}
|
||||
else
|
||||
{
|
||||
intro_sort_impl(gt, end, max_depth - 1, comp);
|
||||
end = lt;
|
||||
}
|
||||
}
|
||||
|
||||
heap_sort(begin, end, comp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -100,3 +100,22 @@ namespace BAN
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
|
||||
template<typename F, typename T>
|
||||
void print_argument(F putc, const Span<T>& span, const ValueFormat& format)
|
||||
{
|
||||
putc('[');
|
||||
for (typename Span<T>::size_type i = 0; i < span.size(); i++)
|
||||
{
|
||||
if (i != 0) putc(',');
|
||||
print_argument(putc, span[i], format);
|
||||
}
|
||||
putc(']');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ To change the bootloader you can set environment variable BANAN\_BOOTLOADER; sup
|
||||
|
||||
To run with UEFI set environment variable BANAN\_UEFI\_BOOT=1. You will also have to set OVMF\_PATH to the correct OVMF (default */usr/share/ovmf/x64/OVMF.fd*).
|
||||
|
||||
To build an image with no physical root filesystem, but an initrd set environment variable BANAN\_INITRD=1. This can be used when testing on hardware with unsupported USB controller.
|
||||
To build an image with no physical root filesystem, but an initrd set environment variable BANAN\_INITRD=1. This can be used when testing on hardware with unsupported USB controller. If BANAN\_INITRD is set to a value larger than 1, initrd will be gzip compressed.
|
||||
|
||||
If you have corrupted your disk image or want to create new one, you can either manually delete *build/banan-os.img* and build system will automatically create you a new one or you can run the following command.
|
||||
```sh
|
||||
|
||||
Binary file not shown.
@@ -59,7 +59,7 @@ signal_trampoline:
|
||||
addl $24, %esp
|
||||
|
||||
// restore sigmask
|
||||
movl $79, %eax // SYS_SIGPROCMASK
|
||||
movl $78, %eax // SYS_SIGPROCMASK
|
||||
movl $3, %ebx // SIG_SETMASK
|
||||
leal 72(%esp), %ecx // set
|
||||
xorl %edx, %edx // oset
|
||||
|
||||
@@ -12,7 +12,7 @@ asm_yield_trampoline:
|
||||
pushl %ebp
|
||||
|
||||
pushl %esp
|
||||
call scheduler_on_yield
|
||||
call scheduler_on_yield_trampoline
|
||||
addl $4, %esp
|
||||
|
||||
popl %ebp
|
||||
|
||||
@@ -27,14 +27,10 @@
|
||||
|
||||
isr_stub:
|
||||
intr_header 12
|
||||
movl %cr0, %eax; pushl %eax
|
||||
movl %cr2, %eax; pushl %eax
|
||||
movl %cr3, %eax; pushl %eax
|
||||
movl %cr4, %eax; pushl %eax
|
||||
|
||||
movl 48(%esp), %edi // isr number
|
||||
movl 52(%esp), %esi // error code
|
||||
leal 56(%esp), %edx // interrupt stack ptr
|
||||
movl 32(%esp), %edi // isr number
|
||||
movl 36(%esp), %esi // error code
|
||||
leal 40(%esp), %edx // interrupt stack ptr
|
||||
movl %esp, %ecx // register ptr
|
||||
|
||||
# stack frame for stack trace
|
||||
@@ -52,7 +48,7 @@ isr_stub:
|
||||
call cpp_isr_handler
|
||||
|
||||
movl %ebp, %esp
|
||||
addl $24, %esp
|
||||
addl $8, %esp
|
||||
|
||||
intr_footer 12
|
||||
addl $8, %esp
|
||||
|
||||
@@ -61,7 +61,7 @@ signal_trampoline:
|
||||
addq $40, %rsp
|
||||
|
||||
// restore sigmask
|
||||
movq $79, %rdi // SYS_SIGPROCMASK
|
||||
movq $78, %rdi // SYS_SIGPROCMASK
|
||||
movq $3, %rsi // SIG_SETMASK
|
||||
leaq 192(%rsp), %rdx // set
|
||||
xorq %r10, %r10 // oset
|
||||
|
||||
@@ -15,7 +15,7 @@ asm_yield_trampoline:
|
||||
pushq %r15
|
||||
|
||||
movq %rsp, %rdi
|
||||
call scheduler_on_yield
|
||||
call scheduler_on_yield_trampoline
|
||||
|
||||
popq %r15
|
||||
popq %r14
|
||||
|
||||
@@ -44,17 +44,12 @@
|
||||
|
||||
isr_stub:
|
||||
intr_header 24
|
||||
movq %cr0, %rax; pushq %rax
|
||||
movq %cr2, %rax; pushq %rax
|
||||
movq %cr3, %rax; pushq %rax
|
||||
movq %cr4, %rax; pushq %rax
|
||||
|
||||
movq 152(%rsp), %rdi // isr number
|
||||
movq 160(%rsp), %rsi // error code
|
||||
leaq 168(%rsp), %rdx // interrupt stack ptr
|
||||
movq %rsp, %rcx // register ptr
|
||||
movq 120(%rsp), %rdi // isr number
|
||||
movq 128(%rsp), %rsi // error code
|
||||
leaq 136(%rsp), %rdx // interrupt stack ptr
|
||||
movq %rsp, %rcx // register ptr
|
||||
call cpp_isr_handler
|
||||
addq $32, %rsp
|
||||
|
||||
intr_footer 24
|
||||
addq $16, %rsp
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Kernel::API
|
||||
enum SharedPageFeature : uint32_t
|
||||
{
|
||||
SPF_GETTIME = 1 << 0,
|
||||
SPF_RDTSCP = 1 << 1,
|
||||
};
|
||||
|
||||
struct SharedPage
|
||||
@@ -18,9 +19,8 @@ namespace Kernel::API
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t shift;
|
||||
uint64_t mult;
|
||||
uint64_t realtime_seconds;
|
||||
uint64_t realtime_s;
|
||||
uint32_t realtime_ns;
|
||||
} gettime_shared;
|
||||
|
||||
struct
|
||||
@@ -28,6 +28,8 @@ namespace Kernel::API
|
||||
struct
|
||||
{
|
||||
uint32_t seq;
|
||||
uint32_t mult;
|
||||
int8_t shift;
|
||||
uint64_t last_ns;
|
||||
uint64_t last_tsc;
|
||||
} gettime_local;
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Kernel
|
||||
BAN::ErrorOr<uint8_t> reserve_gsi(uint32_t gsi);
|
||||
|
||||
void initialize_timer();
|
||||
void set_timer_dealine(uint64_t ns);
|
||||
|
||||
private:
|
||||
uint32_t read_from_local_apic(ptrdiff_t);
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||
|
||||
BAN::ErrorOr<long> ioctl_impl(int cmd, void* arg) override;
|
||||
BAN::ErrorOr<long> ioctl_impl(unsigned long request, void* arg) override;
|
||||
|
||||
protected:
|
||||
ThreadBlocker m_sample_data_blocker;
|
||||
|
||||
@@ -82,5 +82,8 @@ namespace CPUID
|
||||
bool has_pat();
|
||||
bool has_1gib_pages();
|
||||
bool has_invariant_tsc();
|
||||
bool has_rdtscp();
|
||||
uint64_t get_tsc_frequency();
|
||||
bool has_kvm_pvclock();
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Kernel
|
||||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||
|
||||
BAN::ErrorOr<long> ioctl_impl(int cmd, void* arg) override;
|
||||
BAN::ErrorOr<long> ioctl_impl(unsigned long request, void* arg) override;
|
||||
|
||||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace Kernel::ELF
|
||||
size_t size;
|
||||
};
|
||||
|
||||
bool open_execfd;
|
||||
vaddr_t entry_point;
|
||||
BAN::Optional<vaddr_t> interp_base;
|
||||
BAN::Optional<TLS> master_tls;
|
||||
BAN::Vector<BAN::UniqPtr<MemoryRegion>> regions;
|
||||
};
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace Kernel
|
||||
bool has_error() const { return has_error_impl(); }
|
||||
bool has_hungup() const { return has_hungup_impl(); }
|
||||
|
||||
BAN::ErrorOr<long> ioctl(int request, void* arg);
|
||||
BAN::ErrorOr<long> ioctl(unsigned long request, void* arg);
|
||||
|
||||
BAN::ErrorOr<void> add_epoll(class Epoll*);
|
||||
void del_epoll(class Epoll*);
|
||||
@@ -199,7 +199,7 @@ namespace Kernel
|
||||
virtual bool has_error_impl() const = 0;
|
||||
virtual bool has_hungup_impl() const = 0;
|
||||
|
||||
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<long> ioctl_impl(unsigned long, void*) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
|
||||
protected:
|
||||
// TODO: this is supposed to be const I guess?
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace Kernel
|
||||
REG_TDLEN = 0x3808,
|
||||
REG_TDH = 0x3810,
|
||||
REG_TDT = 0x3818,
|
||||
REG_RXCSUM = 0x5000,
|
||||
REG_MTA = 0x5200,
|
||||
};
|
||||
|
||||
@@ -167,6 +168,15 @@ namespace Kernel
|
||||
RCTL_BSIZE_16384 = (0b01 << 16) | RCTL_BSEX,
|
||||
};
|
||||
|
||||
enum E1000_RXCSUM : uint32_t
|
||||
{
|
||||
RXSUM_IPOFLD = 1 << 8,
|
||||
RXSUM_TUOFLD = 1 << 9,
|
||||
RXSUM_CRCOFLD = 1 << 11,
|
||||
RXSUM_IPPCE = 1 << 12,
|
||||
RXSUM_PCSD = 1 << 13,
|
||||
};
|
||||
|
||||
enum E1000_CMD : uint8_t
|
||||
{
|
||||
CMD_EOP = 1 << 0,
|
||||
@@ -178,6 +188,26 @@ namespace Kernel
|
||||
CMD_IDE = 1 << 7,
|
||||
};
|
||||
|
||||
enum E1000_RX_STS : uint8_t
|
||||
{
|
||||
RX_STS_IPCS = 1 << 6,
|
||||
RX_STS_TCPCS = 1 << 5,
|
||||
RX_STS_UDPCS = 1 << 5,
|
||||
RX_STS_EOP = 1 << 1,
|
||||
RX_STS_DD = 1 << 0,
|
||||
};
|
||||
|
||||
enum E1000_RX_ERR : uint8_t
|
||||
{
|
||||
RX_ERR_RXE = 1 << 7,
|
||||
RX_ERR_IPE = 1 << 6,
|
||||
RX_ERR_TCPE = 1 << 5,
|
||||
RX_ERR_CXE = 1 << 4,
|
||||
RX_ERR_SEQ = 1 << 2,
|
||||
RX_ERR_SE = 1 << 1,
|
||||
RX_ERR_CE = 1 << 0,
|
||||
};
|
||||
|
||||
struct e1000_rx_desc
|
||||
{
|
||||
uint64_t addr;
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Kernel
|
||||
uint32_t read32(uint16_t reg);
|
||||
void write32(uint16_t reg, uint32_t value);
|
||||
|
||||
BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) override;
|
||||
BAN::ErrorOr<void> send_raw_bytes(BAN::Span<const BAN::ConstByteSpan> buffers) override;
|
||||
|
||||
bool can_read_impl() const override { return false; }
|
||||
bool can_write_impl() const override { return false; }
|
||||
@@ -74,8 +74,8 @@ namespace Kernel
|
||||
BAN::UniqPtr<DMARegion> m_rx_descriptor_region;
|
||||
BAN::UniqPtr<DMARegion> m_tx_descriptor_region;
|
||||
|
||||
BAN::Atomic<uint32_t> m_tx_head1 { 0 };
|
||||
BAN::Atomic<uint32_t> m_tx_head2 { 0 };
|
||||
BAN::Atomic<uint32_t> m_tx_head { 0 };
|
||||
BAN::Atomic<uint32_t> m_tx_commit { 0 };
|
||||
|
||||
SpinLock m_rx_lock;
|
||||
ThreadBlocker m_rx_blocker;
|
||||
|
||||
@@ -41,14 +41,14 @@ namespace Kernel
|
||||
|
||||
ARPTable& arp_table() { return *m_arp_table; }
|
||||
|
||||
BAN::ErrorOr<void> handle_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan);
|
||||
BAN::ErrorOr<void> handle_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan, uint32_t validated_cksums);
|
||||
|
||||
virtual void unbind_socket(uint16_t port) override;
|
||||
virtual BAN::ErrorOr<void> bind_socket_with_target(BAN::RefPtr<NetworkSocket>, const sockaddr* target_address, socklen_t target_address_len) override;
|
||||
virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) override;
|
||||
virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) override;
|
||||
|
||||
virtual BAN::ErrorOr<size_t> sendto(NetworkSocket&, BAN::ConstByteSpan, const sockaddr*, socklen_t) override;
|
||||
virtual BAN::ErrorOr<void> sendto(NetworkSocket&, BAN::ConstByteSpan, const sockaddr*, socklen_t) override;
|
||||
|
||||
virtual Socket::Domain domain() const override { return Socket::Domain::INET ;}
|
||||
virtual size_t header_size() const override { return sizeof(IPv4Header); }
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Kernel
|
||||
{}
|
||||
~LoopbackInterface();
|
||||
|
||||
BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) override;
|
||||
BAN::ErrorOr<void> send_raw_bytes(BAN::Span<const BAN::ConstByteSpan> buffers) override;
|
||||
|
||||
bool can_read_impl() const override { return false; }
|
||||
bool can_write_impl() const override { return false; }
|
||||
@@ -46,7 +46,7 @@ namespace Kernel
|
||||
};
|
||||
|
||||
private:
|
||||
Mutex m_buffer_lock;
|
||||
SpinLock m_buffer_lock;
|
||||
BAN::UniqPtr<VirtualRange> m_buffer;
|
||||
|
||||
uint32_t m_buffer_tail { 0 };
|
||||
|
||||
@@ -23,6 +23,13 @@ namespace Kernel
|
||||
ARP = 0x0806,
|
||||
};
|
||||
|
||||
enum NetworkChecksum : uint32_t
|
||||
{
|
||||
CKSUM_IPV4 = 1 << 0,
|
||||
CKSUM_TCP = 1 << 1,
|
||||
CKSUM_UDP = 1 << 2,
|
||||
};
|
||||
|
||||
class NetworkInterface : public CharacterDevice
|
||||
{
|
||||
BAN_NON_COPYABLE(NetworkInterface);
|
||||
@@ -59,14 +66,33 @@ namespace Kernel
|
||||
|
||||
virtual BAN::StringView name() const override { return m_name; }
|
||||
|
||||
BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan payload)
|
||||
BAN::ErrorOr<void> send_with_ethernet_header(BAN::MACAddress dst_mac, EtherType ether_type, BAN::ConstByteSpan buffer)
|
||||
{
|
||||
return send_bytes(destination, protocol, { &payload, 1 });
|
||||
BAN::ConstByteSpan buffer_array[1] { buffer };
|
||||
return send_with_ethernet_header(dst_mac, ether_type, buffer_array);
|
||||
}
|
||||
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) = 0;
|
||||
|
||||
template<size_t SIZE>
|
||||
BAN::ErrorOr<void> send_with_ethernet_header(BAN::MACAddress dst_mac, EtherType ether_type, const BAN::ConstByteSpan (&buffer_array)[SIZE])
|
||||
{
|
||||
const auto ethernet_header = EthernetHeader {
|
||||
.dst_mac = dst_mac,
|
||||
.src_mac = get_mac_address(),
|
||||
.ether_type = ether_type,
|
||||
};
|
||||
|
||||
BAN::ConstByteSpan new_buffer_array[SIZE + 1];
|
||||
new_buffer_array[0] = BAN::ConstByteSpan::from(ethernet_header);
|
||||
for (size_t i = 0; i < SIZE; i++)
|
||||
new_buffer_array[i + 1] = buffer_array[i];
|
||||
|
||||
return send_raw_bytes({ new_buffer_array, SIZE + 1 });
|
||||
}
|
||||
|
||||
virtual BAN::ErrorOr<void> send_raw_bytes(BAN::Span<const BAN::ConstByteSpan> buffers) = 0;
|
||||
|
||||
private:
|
||||
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
||||
BAN::ErrorOr<long> ioctl_impl(unsigned long, void*) override;
|
||||
|
||||
private:
|
||||
const Type m_type;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Kernel
|
||||
virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) = 0;
|
||||
virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) = 0;
|
||||
|
||||
virtual BAN::ErrorOr<size_t> sendto(NetworkSocket&, BAN::ConstByteSpan, const sockaddr*, socklen_t) = 0;
|
||||
virtual BAN::ErrorOr<void> sendto(NetworkSocket&, BAN::ConstByteSpan, const sockaddr*, socklen_t) = 0;
|
||||
|
||||
virtual Socket::Domain domain() const = 0;
|
||||
virtual size_t header_size() const = 0;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Kernel
|
||||
BAN::ErrorOr<BAN::RefPtr<Socket>> create_socket(Socket::Domain, Socket::Type, mode_t, uid_t, gid_t);
|
||||
BAN::ErrorOr<void> connect_sockets(Socket::Domain, BAN::RefPtr<Socket>, BAN::RefPtr<Socket>);
|
||||
|
||||
void on_receive(NetworkInterface&, BAN::ConstByteSpan);
|
||||
void on_receive(NetworkInterface&, BAN::ConstByteSpan, uint32_t validated_cksums);
|
||||
|
||||
private:
|
||||
NetworkManager() {}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Kernel
|
||||
virtual void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader) = 0;
|
||||
virtual NetworkProtocol protocol() const = 0;
|
||||
|
||||
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) = 0;
|
||||
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len, uint32_t validated_cksums) = 0;
|
||||
|
||||
bool is_bound() const { return m_address_len >= static_cast<socklen_t>(sizeof(sa_family_t)) && m_address.ss_family != AF_UNSPEC; }
|
||||
in_port_t bound_port() const
|
||||
@@ -54,7 +54,7 @@ namespace Kernel
|
||||
protected:
|
||||
NetworkSocket(NetworkLayer&, const Socket::Info&);
|
||||
|
||||
virtual BAN::ErrorOr<long> ioctl_impl(int request, void* arg) override;
|
||||
virtual BAN::ErrorOr<long> ioctl_impl(unsigned long request, void* arg) override;
|
||||
virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) override;
|
||||
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override = 0;
|
||||
|
||||
|
||||
@@ -7,25 +7,25 @@ namespace Kernel
|
||||
|
||||
enum RTL8169_IO_REGS : uint16_t
|
||||
{
|
||||
RTL8169_IO_IDR0 = 0x00,
|
||||
RTL8169_IO_IDR1 = 0x01,
|
||||
RTL8169_IO_IDR2 = 0x02,
|
||||
RTL8169_IO_IDR3 = 0x03,
|
||||
RTL8169_IO_IDR4 = 0x04,
|
||||
RTL8169_IO_IDR5 = 0x05,
|
||||
RTL8169_IO_IDR0 = 0x00,
|
||||
RTL8169_IO_IDR1 = 0x01,
|
||||
RTL8169_IO_IDR2 = 0x02,
|
||||
RTL8169_IO_IDR3 = 0x03,
|
||||
RTL8169_IO_IDR4 = 0x04,
|
||||
RTL8169_IO_IDR5 = 0x05,
|
||||
|
||||
RTL8169_IO_TNPDS = 0x20,
|
||||
RTL8169_IO_CR = 0x37,
|
||||
RTL8169_IO_TPPoll = 0x38,
|
||||
RTL8169_IO_IMR = 0x3C,
|
||||
RTL8169_IO_ISR = 0x3E,
|
||||
RTL8169_IO_TCR = 0x40,
|
||||
RTL8169_IO_RCR = 0x44,
|
||||
RTL8169_IO_9346CR = 0x50,
|
||||
RTL8169_IO_PHYSts = 0x6C,
|
||||
RTL8169_IO_RMS = 0xDA,
|
||||
RTL8169_IO_RDSAR = 0xE4,
|
||||
RTL8169_IO_MTPS = 0xEC,
|
||||
RTL8169_IO_TNPDS = 0x20,
|
||||
RTL8169_IO_CR = 0x37,
|
||||
RTL8169_IO_TPPoll = 0x38,
|
||||
RTL8169_IO_IMR = 0x3C,
|
||||
RTL8169_IO_ISR = 0x3E,
|
||||
RTL8169_IO_TCR = 0x40,
|
||||
RTL8169_IO_RCR = 0x44,
|
||||
RTL8169_IO_PHYSts = 0x6C,
|
||||
RTL8169_IO_RMS = 0xDA,
|
||||
RTL8169_IO_CPlusCR = 0xE0,
|
||||
RTL8169_IO_RDSAR = 0xE4,
|
||||
RTL8169_IO_MTPS = 0xEC,
|
||||
};
|
||||
|
||||
enum RTL8169_CR : uint8_t
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Kernel
|
||||
virtual bool link_up() override { return m_link_up; }
|
||||
virtual int link_speed() override;
|
||||
|
||||
virtual size_t payload_mtu() const override { return 7436 - sizeof(EthernetHeader); }
|
||||
virtual size_t payload_mtu() const override { return 0x1FF8 - sizeof(EthernetHeader); }
|
||||
|
||||
virtual void handle_irq() override;
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan>) override;
|
||||
virtual BAN::ErrorOr<void> send_raw_bytes(BAN::Span<const BAN::ConstByteSpan> buffers) override;
|
||||
|
||||
virtual bool can_read_impl() const override { return false; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
@@ -64,14 +64,17 @@ namespace Kernel
|
||||
BAN::UniqPtr<DMARegion> m_rx_descriptor_region;
|
||||
BAN::UniqPtr<DMARegion> m_tx_descriptor_region;
|
||||
|
||||
SpinLock m_lock;
|
||||
BAN::Atomic<bool> m_rx_thread_should_die { false };
|
||||
BAN::Atomic<bool> m_rx_thread_is_dead { true };
|
||||
|
||||
bool m_thread_should_die { false };
|
||||
BAN::Atomic<bool> m_thread_is_dead { true };
|
||||
ThreadBlocker m_thread_blocker;
|
||||
uint32_t m_rx_head { 0 };
|
||||
SpinLock m_rx_lock;
|
||||
ThreadBlocker m_rx_blocker;
|
||||
|
||||
uint32_t m_rx_current { 0 };
|
||||
size_t m_tx_current { 0 };
|
||||
BAN::Atomic<uint32_t> m_tx_head { 0 };
|
||||
BAN::Atomic<uint32_t> m_tx_commit { 0 };
|
||||
SpinLock m_tx_lock;
|
||||
ThreadBlocker m_tx_blocker;
|
||||
|
||||
BAN::MACAddress m_mac_address {};
|
||||
BAN::Atomic<bool> m_link_up { false };
|
||||
|
||||
@@ -66,9 +66,9 @@ namespace Kernel
|
||||
BAN::ErrorOr<void> getsockopt_impl(int, int, void*, socklen_t*) override;
|
||||
BAN::ErrorOr<void> setsockopt_impl(int, int, const void*, socklen_t) override;
|
||||
|
||||
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
||||
BAN::ErrorOr<long> ioctl_impl(unsigned long, void*) override;
|
||||
|
||||
void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;
|
||||
void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len, uint32_t validated_cksums) override;
|
||||
|
||||
bool can_read_impl() const override;
|
||||
bool can_write_impl() const override;
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Kernel
|
||||
void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader) override;
|
||||
|
||||
protected:
|
||||
void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;
|
||||
void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len, uint32_t validated_cksums) override;
|
||||
|
||||
BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override;
|
||||
BAN::ErrorOr<void> bind_impl(const sockaddr* address, socklen_t address_len) override;
|
||||
@@ -41,7 +41,7 @@ namespace Kernel
|
||||
BAN::ErrorOr<void> getsockopt_impl(int, int, void*, socklen_t*) override;
|
||||
BAN::ErrorOr<void> setsockopt_impl(int, int, const void*, socklen_t) override;
|
||||
|
||||
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
||||
BAN::ErrorOr<long> ioctl_impl(unsigned long, void*) override;
|
||||
|
||||
bool can_read_impl() const override { return !m_packets.empty(); }
|
||||
bool can_write_impl() const override { return true; }
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace Kernel
|
||||
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override;
|
||||
virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override;
|
||||
virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override;
|
||||
virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) override;
|
||||
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
|
||||
virtual BAN::ErrorOr<void> getsockopt_impl(int, int, void*, socklen_t*) override;
|
||||
virtual BAN::ErrorOr<void> setsockopt_impl(int, int, const void*, socklen_t) override;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/Memory/Types.h>
|
||||
#include <kernel/Storage/StorageController.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
@@ -179,7 +178,7 @@ namespace Kernel::PCI
|
||||
private:
|
||||
struct PCIeInfo
|
||||
{
|
||||
paddr_t bus_paddr[256];
|
||||
paddr_t bus_paddr[256] {};
|
||||
};
|
||||
|
||||
PCIManager() = default;
|
||||
|
||||
@@ -44,10 +44,10 @@ namespace Kernel
|
||||
~Process();
|
||||
void cleanup_function(Thread*);
|
||||
|
||||
void register_to_scheduler();
|
||||
BAN::ErrorOr<vaddr_t> setup_initial_process_stack(MemoryBackedRegion&, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv);
|
||||
|
||||
void exit(int status, int signal);
|
||||
|
||||
void add_thread(Thread*);
|
||||
// returns true if thread was the last one
|
||||
bool on_thread_exit(Thread&);
|
||||
|
||||
@@ -68,7 +68,6 @@ namespace Kernel
|
||||
BAN::ErrorOr<long> sys_exec(const char* path, const char* const* argv, const char* const* envp);
|
||||
|
||||
BAN::ErrorOr<long> sys_wait(pid_t pid, int* stat_loc, int options);
|
||||
BAN::ErrorOr<long> sys_sleep(int seconds);
|
||||
BAN::ErrorOr<long> sys_nanosleep(const timespec* rqtp, timespec* rmtp);
|
||||
BAN::ErrorOr<long> sys_setitimer(int which, const itimerval* value, itimerval* ovalue);
|
||||
|
||||
@@ -137,7 +136,7 @@ namespace Kernel
|
||||
BAN::ErrorOr<long> sys_recvmsg(int socket, msghdr* message, int flags);
|
||||
BAN::ErrorOr<long> sys_sendmsg(int socket, const msghdr* message, int flags);
|
||||
|
||||
BAN::ErrorOr<long> sys_ioctl(int fildes, int request, void* arg);
|
||||
BAN::ErrorOr<long> sys_ioctl(int fildes, unsigned long request, void* arg);
|
||||
|
||||
BAN::ErrorOr<long> sys_pselect(sys_pselect_t* arguments);
|
||||
BAN::ErrorOr<long> sys_ppoll(pollfd* fds, nfds_t nfds, const timespec* tmp_p, const sigset_t* sigmask);
|
||||
@@ -210,12 +209,12 @@ namespace Kernel
|
||||
BAN::ErrorOr<long> sys_set_gsbase(void*);
|
||||
BAN::ErrorOr<long> sys_get_gsbase();
|
||||
|
||||
BAN::ErrorOr<long> sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg);
|
||||
BAN::ErrorOr<long> sys_pthread_exit(void* value);
|
||||
BAN::ErrorOr<long> sys_pthread_join(pthread_t thread, void** value);
|
||||
BAN::ErrorOr<long> sys_pthread_self();
|
||||
BAN::ErrorOr<long> sys_pthread_kill(pthread_t thread, int signal);
|
||||
BAN::ErrorOr<long> sys_pthread_detach(pthread_t thread);
|
||||
BAN::ErrorOr<long> sys_thread_create(void (*entry)(void*), void* arg, void* stack_base, size_t stack_size);
|
||||
BAN::ErrorOr<long> sys_thread_exit(void* value);
|
||||
BAN::ErrorOr<long> sys_thread_join(pid_t tid, void** value);
|
||||
BAN::ErrorOr<long> sys_thread_getid();
|
||||
BAN::ErrorOr<long> sys_thread_kill(pid_t tid, int signal);
|
||||
BAN::ErrorOr<long> sys_thread_detach(pid_t tid);
|
||||
|
||||
BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*);
|
||||
|
||||
@@ -229,11 +228,12 @@ namespace Kernel
|
||||
|
||||
vaddr_t shared_page_vaddr() const { return m_shared_page_vaddr; }
|
||||
|
||||
PageTable& page_table() { return m_page_table ? *m_page_table : PageTable::kernel(); }
|
||||
PageTable& page_table() { return *m_page_table; }
|
||||
|
||||
size_t proc_meminfo(off_t offset, BAN::ByteSpan) const;
|
||||
size_t proc_cmdline(off_t offset, BAN::ByteSpan) const;
|
||||
size_t proc_environ(off_t offset, BAN::ByteSpan) const;
|
||||
size_t proc_cputime(off_t offset, BAN::ByteSpan) const;
|
||||
BAN::ErrorOr<BAN::String> proc_cwd() const;
|
||||
BAN::ErrorOr<BAN::String> proc_exe() const;
|
||||
|
||||
@@ -364,13 +364,13 @@ namespace Kernel
|
||||
|
||||
BAN::Vector<Thread*> m_threads;
|
||||
|
||||
struct pthread_info_t
|
||||
struct exited_thread_info_t
|
||||
{
|
||||
pthread_t thread;
|
||||
pid_t tid;
|
||||
void* value;
|
||||
};
|
||||
BAN::Vector<pthread_info_t> m_exited_pthreads;
|
||||
ThreadBlocker m_pthread_exit_blocker;
|
||||
BAN::Vector<exited_thread_info_t> m_exited_threads;
|
||||
ThreadBlocker m_thread_exit_blocker;
|
||||
|
||||
uint64_t m_alarm_interval_ns { 0 };
|
||||
uint64_t m_alarm_wake_time_ns { 0 };
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace Kernel
|
||||
static void yield();
|
||||
static Scheduler& scheduler() { return *read_gs_sized<Scheduler*>(offsetof(Processor, m_scheduler)); }
|
||||
|
||||
static void initialize_tsc(uint8_t shift, uint64_t mult, uint64_t realtime_seconds);
|
||||
static void initialize_tsc(uint64_t realtime_seconds);
|
||||
static void update_tsc();
|
||||
static uint64_t ns_since_boot_tsc();
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Kernel
|
||||
|
||||
public:
|
||||
void add_thread_to_back(Node*);
|
||||
void add_thread_with_wake_time(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*);
|
||||
@@ -60,7 +60,8 @@ namespace Kernel
|
||||
void reschedule(YieldRegisters*);
|
||||
void reschedule_if_idle();
|
||||
|
||||
void timer_interrupt();
|
||||
void on_timer_interrupt();
|
||||
void on_yield(YieldRegisters*);
|
||||
|
||||
static BAN::ErrorOr<void> bind_thread_to_processor(Thread*, ProcessorID);
|
||||
// if thread is already bound, this will never fail
|
||||
@@ -82,6 +83,7 @@ namespace Kernel
|
||||
void update_most_loaded_node_queue(SchedulerQueue::Node*, SchedulerQueue* target_queue);
|
||||
void remove_node_from_most_loaded(SchedulerQueue::Node*);
|
||||
|
||||
void update_wake_up_deadline();
|
||||
void wake_up_sleeping_threads();
|
||||
|
||||
void do_load_balancing();
|
||||
|
||||
@@ -10,12 +10,14 @@
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class AHCIController final : public StorageController, public Interruptable
|
||||
class AHCIController final : public BAN::RefCounted<AHCIController>, public Interruptable
|
||||
{
|
||||
BAN_NON_COPYABLE(AHCIController);
|
||||
BAN_NON_MOVABLE(AHCIController);
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<AHCIController>> create(PCI::Device&);
|
||||
|
||||
~AHCIController();
|
||||
|
||||
virtual void handle_irq() override;
|
||||
@@ -27,6 +29,7 @@ namespace Kernel
|
||||
: m_pci_device(pci_device)
|
||||
{ }
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
BAN::Optional<AHCIPortType> check_port_type(volatile HBAPortMemorySpace&);
|
||||
|
||||
private:
|
||||
|
||||
@@ -56,8 +56,6 @@ namespace Kernel
|
||||
|
||||
// Non-owning pointers
|
||||
BAN::Vector<ATADevice*> m_devices;
|
||||
|
||||
friend class ATAController;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -2,23 +2,22 @@
|
||||
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <kernel/PCI.h>
|
||||
#include <kernel/Storage/StorageController.h>
|
||||
#include <kernel/Storage/ATA/ATABus.h>
|
||||
#include <kernel/Storage/ATA/ATADevice.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class ATAController : public StorageController
|
||||
class ATAController : public BAN::RefCounted<ATAController>
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<StorageController>> create(PCI::Device&);
|
||||
virtual BAN::ErrorOr<void> initialize() override;
|
||||
static BAN::ErrorOr<BAN::RefPtr<ATAController>> create(PCI::Device&);
|
||||
|
||||
private:
|
||||
ATAController(PCI::Device& pci_device)
|
||||
: m_pci_device(pci_device)
|
||||
{ }
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
private:
|
||||
PCI::Device& m_pci_device;
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class NVMeController final : public StorageController, public CharacterDevice
|
||||
class NVMeController final : public CharacterDevice
|
||||
{
|
||||
BAN_NON_COPYABLE(NVMeController);
|
||||
BAN_NON_MOVABLE(NVMeController);
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<StorageController>> create(PCI::Device&);
|
||||
static BAN::ErrorOr<BAN::RefPtr<NVMeController>> create(PCI::Device&);
|
||||
|
||||
NVMeQueue& io_queue() { return *m_io_queue; }
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Kernel
|
||||
|
||||
private:
|
||||
NVMeController(PCI::Device& pci_device);
|
||||
virtual BAN::ErrorOr<void> initialize() override;
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
BAN::ErrorOr<void> identify_controller();
|
||||
BAN::ErrorOr<void> identify_namespaces();
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/RefPtr.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class StorageController : public BAN::RefCounted<StorageController>
|
||||
{
|
||||
public:
|
||||
virtual ~StorageController() {}
|
||||
virtual BAN::ErrorOr<void> initialize() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -32,7 +32,7 @@ namespace Kernel
|
||||
|
||||
void on_close(int) override;
|
||||
|
||||
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
||||
BAN::ErrorOr<long> ioctl_impl(unsigned long, void*) override;
|
||||
|
||||
private:
|
||||
PseudoTerminalMaster(BAN::UniqPtr<VirtualRange>, mode_t, uid_t, gid_t);
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace Kernel
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hungup_impl() const override { return false; }
|
||||
|
||||
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
||||
virtual BAN::ErrorOr<long> ioctl_impl(unsigned long, void*) override;
|
||||
|
||||
private:
|
||||
bool putchar(uint8_t ch);
|
||||
|
||||
@@ -41,22 +41,20 @@ namespace Kernel
|
||||
// TODO: userspace stack size is hard limited, maybe make this dynamic?
|
||||
#if ARCH(x86_64)
|
||||
static constexpr size_t userspace_stack_size { 32 << 20 };
|
||||
static constexpr vaddr_t userspace_stack_base { 0x0000700000000000 };
|
||||
#elif ARCH(i686)
|
||||
static constexpr size_t userspace_stack_size { 4 << 20 };
|
||||
static constexpr vaddr_t userspace_stack_base { 0xB0000000 };
|
||||
#endif
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<Thread*> create_kernel(entry_t, void*);
|
||||
static BAN::ErrorOr<Thread*> create_userspace(Process*, PageTable&);
|
||||
static BAN::ErrorOr<Thread*> create_userspace(Process*, PageTable&, vaddr_t userspace_stack_vaddr, size_t userspace_stack_size, vaddr_t entry_point, vaddr_t stack_pointer);
|
||||
~Thread();
|
||||
|
||||
BAN::ErrorOr<Thread*> pthread_create(entry_t, void*);
|
||||
|
||||
BAN::ErrorOr<Thread*> clone(Process*, uintptr_t sp, uintptr_t ip);
|
||||
void setup_process_cleanup();
|
||||
|
||||
BAN::ErrorOr<void> initialize_userspace(vaddr_t entry, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv);
|
||||
|
||||
// Returns true, if thread is going to trigger signal
|
||||
bool is_interrupted_by_signal(bool skip_stop_and_cont = false) const;
|
||||
|
||||
@@ -77,15 +75,21 @@ namespace Kernel
|
||||
|
||||
// blocks current thread and returns either on unblock, eintr, spuriously or after timeout
|
||||
// if mutex is not nullptr, it will be atomically freed before blocking and automatically locked on wake
|
||||
BAN::ErrorOr<void> sleep_or_eintr_ns(uint64_t ns);
|
||||
BAN::ErrorOr<void> sleep_or_eintr_for_ns(uint64_t timeout_ns);
|
||||
BAN::ErrorOr<void> sleep_or_eintr_until_ns(uint64_t waketime_ns);
|
||||
BAN::ErrorOr<void> block_or_eintr_indefinite(ThreadBlocker& thread_blocker, BaseMutex* mutex);
|
||||
BAN::ErrorOr<void> block_or_eintr_or_timeout_ns(ThreadBlocker& thread_blocker, uint64_t timeout_ns, bool etimedout, BaseMutex* mutex);
|
||||
BAN::ErrorOr<void> block_or_eintr_or_waketime_ns(ThreadBlocker& thread_blocker, uint64_t wake_time_ns, bool etimedout, BaseMutex* mutex);
|
||||
|
||||
BAN::ErrorOr<void> sleep_or_eintr_ms(uint64_t ms)
|
||||
BAN::ErrorOr<void> sleep_or_eintr_for_ms(uint64_t timeout_ms)
|
||||
{
|
||||
ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(ms, 1'000'000));
|
||||
return sleep_or_eintr_ns(ms * 1'000'000);
|
||||
ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(timeout_ms, 1'000'000));
|
||||
return sleep_or_eintr_for_ns(timeout_ms * 1'000'000);
|
||||
}
|
||||
BAN::ErrorOr<void> sleep_or_eintr_until_ms(uint64_t waketime_ms)
|
||||
{
|
||||
ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(waketime_ms, 1'000'000));
|
||||
return sleep_or_eintr_until_ns(waketime_ms * 1'000'000);
|
||||
}
|
||||
BAN::ErrorOr<void> block_or_eintr_or_timeout_ms(ThreadBlocker& thread_blocker, uint64_t timeout_ms, bool etimedout, BaseMutex* mutex)
|
||||
{
|
||||
@@ -106,8 +110,6 @@ namespace Kernel
|
||||
vaddr_t kernel_stack_top() const { return m_kernel_stack->vaddr() + m_kernel_stack->size(); }
|
||||
VirtualRange& kernel_stack() { return *m_kernel_stack; }
|
||||
|
||||
MemoryBackedRegion& userspace_stack() { ASSERT(is_userspace() && m_userspace_stack); return *m_userspace_stack; }
|
||||
|
||||
static Thread& current();
|
||||
static pid_t current_tid();
|
||||
|
||||
@@ -151,8 +153,6 @@ namespace Kernel
|
||||
private:
|
||||
Thread(pid_t tid, Process*);
|
||||
|
||||
void setup_exec(vaddr_t ip, vaddr_t sp);
|
||||
|
||||
static void on_exit_trampoline(Thread*);
|
||||
void on_exit();
|
||||
|
||||
@@ -174,7 +174,6 @@ namespace Kernel
|
||||
BAN::UniqPtr<PageTable> m_keep_alive_page_table;
|
||||
|
||||
BAN::UniqPtr<VirtualRange> m_kernel_stack;
|
||||
MemoryBackedRegion* m_userspace_stack { nullptr };
|
||||
const pid_t m_tid { 0 };
|
||||
State m_state { State::NotStarted };
|
||||
Process* m_process { nullptr };
|
||||
@@ -182,6 +181,9 @@ namespace Kernel
|
||||
BAN::Atomic<bool> m_is_detached { false };
|
||||
bool m_delete_process { false };
|
||||
|
||||
vaddr_t m_userspace_stack_vaddr { 0 };
|
||||
size_t m_userspace_stack_size { 0 };
|
||||
|
||||
vaddr_t m_fsbase { 0 };
|
||||
vaddr_t m_gsbase { 0 };
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Kernel
|
||||
class HPET final : public Timer, public Interruptable
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::UniqPtr<HPET>> create(bool force_pic);
|
||||
static BAN::ErrorOr<BAN::UniqPtr<HPET>> create();
|
||||
~HPET();
|
||||
|
||||
virtual uint64_t ms_since_boot() const override;
|
||||
@@ -26,7 +26,7 @@ namespace Kernel
|
||||
|
||||
private:
|
||||
HPET() = default;
|
||||
BAN::ErrorOr<void> initialize(bool force_pic);
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
volatile HPETRegisters& registers();
|
||||
const volatile HPETRegisters& registers() const;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/Memory/DMARegion.h>
|
||||
#include <kernel/Timer/RTC.h>
|
||||
|
||||
#include <time.h>
|
||||
@@ -31,7 +32,14 @@ namespace Kernel
|
||||
class SystemTimer : public Timer
|
||||
{
|
||||
public:
|
||||
static void initialize(bool force_pic);
|
||||
struct TSCInfo
|
||||
{
|
||||
int8_t shift;
|
||||
uint32_t mult;
|
||||
};
|
||||
|
||||
public:
|
||||
static void initialize();
|
||||
static SystemTimer& get();
|
||||
static bool is_initialized();
|
||||
|
||||
@@ -44,29 +52,60 @@ namespace Kernel
|
||||
virtual bool pre_scheduler_sleep_needs_lock() const override;
|
||||
virtual void pre_scheduler_sleep_ns(uint64_t) override;
|
||||
|
||||
void sleep_ms(uint64_t ms) const { ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(ms, 1'000'000)); return sleep_ns(ms * 1'000'000); }
|
||||
void sleep_ns(uint64_t ns) const;
|
||||
void sleep_for_ns(uint64_t timeout_ns) const;
|
||||
void sleep_until_ns(uint64_t waketime_ns) const;
|
||||
|
||||
void sleep_for_ms(uint64_t timeout_ms) const
|
||||
{
|
||||
ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(timeout_ms, 1'000'000));
|
||||
return sleep_for_ns(timeout_ms * 1'000'000);
|
||||
}
|
||||
void sleep_until_ms(uint64_t waketime_ms) const
|
||||
{
|
||||
ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(waketime_ms, 1'000'000));
|
||||
return sleep_until_ns(waketime_ms * 1'000'000);
|
||||
}
|
||||
|
||||
void dont_invoke_scheduler() { m_timer->m_should_invoke_scheduler = false; }
|
||||
|
||||
void update_tsc() const;
|
||||
uint64_t ns_since_boot_no_tsc() const;
|
||||
void update_tsc();
|
||||
TSCInfo tsc_info() const;
|
||||
|
||||
uint64_t ns_since_boot_no_tsc() const { return m_timer->ns_since_boot(); }
|
||||
|
||||
timespec real_time() const;
|
||||
|
||||
private:
|
||||
SystemTimer() = default;
|
||||
|
||||
void initialize_timers(bool force_pic);
|
||||
void initialize_timers();
|
||||
|
||||
uint64_t get_tsc_frequency() const;
|
||||
void initialize_invariant_tsc();
|
||||
void initialize_pvclock();
|
||||
|
||||
private:
|
||||
enum class TSCType
|
||||
{
|
||||
None,
|
||||
Invariant,
|
||||
PVClock,
|
||||
};
|
||||
|
||||
uint64_t m_boot_time { 0 };
|
||||
BAN::UniqPtr<RTC> m_rtc;
|
||||
BAN::UniqPtr<Timer> m_timer;
|
||||
bool m_has_invariant_tsc { false };
|
||||
mutable uint32_t m_timer_ticks { 0 };
|
||||
|
||||
TSCType m_tsc_type = TSCType::None;
|
||||
|
||||
union {
|
||||
struct {
|
||||
int8_t shift;
|
||||
uint32_t mult;
|
||||
} invariant;
|
||||
} m_tsc_info;
|
||||
|
||||
BAN::UniqPtr<DMARegion> m_tsc_page;
|
||||
uint64_t m_tsc_update_ns { 0 };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Kernel
|
||||
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||
bool can_read_impl() const override { return true; }
|
||||
|
||||
BAN::ErrorOr<long> ioctl_impl(int request, void* arg) override;
|
||||
BAN::ErrorOr<long> ioctl_impl(unsigned long request, void* arg) override;
|
||||
|
||||
private:
|
||||
USBJoystick(USBHIDDriver&);
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Kernel
|
||||
const uint64_t m_block_count;
|
||||
const uint32_t m_block_size;
|
||||
|
||||
const char m_name[4];
|
||||
char m_name[4];
|
||||
|
||||
friend class BAN::RefPtr<USBSCSIDevice>;
|
||||
};
|
||||
|
||||
@@ -952,7 +952,7 @@ acpi_release_global_lock:
|
||||
{
|
||||
if (IO::inw(fadt().pm1a_cnt_blk) & PM1_CNT_SCI_EN)
|
||||
break;
|
||||
SystemTimer::get().sleep_ms(10);
|
||||
SystemTimer::get().sleep_for_ms(10);
|
||||
}
|
||||
|
||||
if (!(IO::inw(fadt().pm1a_cnt_blk) & PM1_CNT_SCI_EN))
|
||||
|
||||
@@ -2146,9 +2146,9 @@ namespace Kernel::ACPI::AML
|
||||
|
||||
auto milliseconds = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t)));
|
||||
|
||||
const uint64_t wakeup_ms = SystemTimer::get().ms_since_boot() + milliseconds.as.integer.value;
|
||||
for (uint64_t curr_ms = SystemTimer::get().ms_since_boot(); curr_ms < wakeup_ms; curr_ms = SystemTimer::get().ms_since_boot())
|
||||
SystemTimer::get().sleep_ms(wakeup_ms - curr_ms);
|
||||
const uint64_t waketime_ms = SystemTimer::get().ms_since_boot() + milliseconds.as.integer.value;
|
||||
while (SystemTimer::get().ms_since_boot() < waketime_ms)
|
||||
SystemTimer::get().sleep_until_ms(waketime_ms);
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -2392,7 +2392,7 @@ namespace Kernel::ACPI::AML
|
||||
result.type = Node::Type::Integer;
|
||||
result.as.integer.value = BAN::numeric_limits<uint64_t>::max();
|
||||
|
||||
const uint64_t wake_time_ms = (timeout_ms >= 0xFFFF)
|
||||
const uint64_t waketime_ms = (timeout_ms >= 0xFFFF)
|
||||
? BAN::numeric_limits<uint64_t>::max()
|
||||
: SystemTimer::get().ms_since_boot() + timeout_ms;
|
||||
|
||||
@@ -2401,9 +2401,9 @@ namespace Kernel::ACPI::AML
|
||||
{
|
||||
if (sync_object->node.as.mutex->mutex.try_lock())
|
||||
break;
|
||||
if (SystemTimer::get().ms_since_boot() >= wake_time_ms)
|
||||
if (SystemTimer::get().ms_since_boot() >= waketime_ms)
|
||||
return result;
|
||||
SystemTimer::get().sleep_ms(1);
|
||||
Processor::yield();
|
||||
}
|
||||
|
||||
if (sync_object->node.as.mutex->global_lock)
|
||||
|
||||
@@ -437,8 +437,27 @@ namespace Kernel
|
||||
|
||||
dprintln("CPU {}: lapic timer frequency: {} Hz", Kernel::Processor::current_id(), m_lapic_timer_frequency_hz);
|
||||
|
||||
write_to_local_apic(LAPIC_TIMER_LVT, TimerModePeriodic | IRQ_TIMER);
|
||||
write_to_local_apic(LAPIC_TIMER_INITIAL_REG, m_lapic_timer_frequency_hz / 2 / 100);
|
||||
write_to_local_apic(LAPIC_TIMER_LVT, TimerModeOneShot | IRQ_TIMER);
|
||||
write_to_local_apic(LAPIC_TIMER_INITIAL_REG, 0);
|
||||
}
|
||||
|
||||
void APIC::set_timer_dealine(uint64_t target_ns)
|
||||
{
|
||||
// TODO: don't hardcode divide by 2
|
||||
const uint64_t effective_freq = m_lapic_timer_frequency_hz / 2;
|
||||
|
||||
const uint64_t delta_ns = [&]() -> uint64_t {
|
||||
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
||||
if (current_ns >= target_ns)
|
||||
return 1;
|
||||
const uint64_t delta_ns = target_ns - current_ns;
|
||||
if (BAN::Math::will_multiplication_overflow(delta_ns, effective_freq))
|
||||
return BAN::numeric_limits<uint64_t>::max() / effective_freq;
|
||||
return delta_ns;
|
||||
}();
|
||||
|
||||
const uint64_t ticks = BAN::Math::div_round_up<uint64_t>(delta_ns * effective_freq, 1'000'000'000);
|
||||
write_to_local_apic(LAPIC_TIMER_INITIAL_REG, BAN::Math::min<uint64_t>(ticks, BAN::numeric_limits<uint32_t>::max()));
|
||||
}
|
||||
|
||||
uint32_t APIC::read_from_local_apic(ptrdiff_t offset)
|
||||
|
||||
@@ -77,9 +77,9 @@ namespace Kernel
|
||||
return to_copy;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> AudioController::ioctl_impl(int cmd, void* arg)
|
||||
BAN::ErrorOr<long> AudioController::ioctl_impl(unsigned long request, void* arg)
|
||||
{
|
||||
switch (cmd)
|
||||
switch (request)
|
||||
{
|
||||
case SND_GET_CHANNELS:
|
||||
*static_cast<uint32_t*>(arg) = get_channels();
|
||||
@@ -92,7 +92,7 @@ namespace Kernel
|
||||
{
|
||||
SpinLockGuard _(m_spinlock);
|
||||
*static_cast<uint32_t*>(arg) = m_sample_data->size();
|
||||
if (cmd == SND_RESET_BUFFER)
|
||||
if (request == SND_RESET_BUFFER)
|
||||
m_sample_data->pop(m_sample_data->size());
|
||||
return 0;
|
||||
}
|
||||
@@ -113,7 +113,7 @@ namespace Kernel
|
||||
return 0;
|
||||
}
|
||||
|
||||
return CharacterDevice::ioctl_impl(cmd, arg);
|
||||
return CharacterDevice::ioctl_impl(request, arg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -448,7 +448,7 @@ namespace Kernel
|
||||
continue;
|
||||
const auto& amp = path[i]->output_amplifier.value();
|
||||
|
||||
const int32_t step_mdB = amp.step_size * 250;
|
||||
const int32_t step_mdB = (amp.step_size + 1) * 250;
|
||||
m_volume_info.step_mdB = step_mdB;
|
||||
m_volume_info.min_mdB = -amp.offset * step_mdB;
|
||||
m_volume_info.max_mdB = (amp.num_steps - amp.offset) * step_mdB;
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Kernel
|
||||
// 4.3 The software must wait at least 521 us (25 frames) after reading CRST as a 1
|
||||
// before assuming that codecs have all made status change requests and have been
|
||||
// registered by the controller
|
||||
SystemTimer::get().sleep_ms(1);
|
||||
SystemTimer::get().sleep_for_ns(521'000);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -85,6 +85,38 @@ namespace CPUID
|
||||
return buffer[3] & (1 << 8);
|
||||
}
|
||||
|
||||
bool has_rdtscp()
|
||||
{
|
||||
uint32_t buffer[4] {};
|
||||
get_cpuid(0x80000000, buffer);
|
||||
if (buffer[0] < 0x80000001)
|
||||
return false;
|
||||
get_cpuid(0x80000001, buffer);
|
||||
return buffer[3] & (1 << 27);
|
||||
}
|
||||
|
||||
uint64_t get_tsc_frequency()
|
||||
{
|
||||
uint32_t buffer[4];
|
||||
get_cpuid(0x00, buffer);
|
||||
if (buffer[0] < 0x15)
|
||||
return 0;
|
||||
get_cpuid(0x15, buffer);
|
||||
if (buffer[0] == 0 || buffer[1] == 0 || buffer[2] == 0)
|
||||
return 0;
|
||||
return static_cast<uint64_t>(buffer[2]) * buffer[1] / buffer[0];
|
||||
}
|
||||
|
||||
bool has_kvm_pvclock()
|
||||
{
|
||||
uint32_t buffer[4] {};
|
||||
get_cpuid(0x40000000, buffer);
|
||||
if (buffer[1] != 0x4B4D564B || buffer[2] != 0x564B4D56 || buffer[3] != 0x4D)
|
||||
return false;
|
||||
get_cpuid(0x40000001, buffer);
|
||||
return buffer[0] & (1 << 3);
|
||||
}
|
||||
|
||||
const char* feature_string_ecx(uint32_t feat)
|
||||
{
|
||||
switch (feat)
|
||||
|
||||
@@ -135,9 +135,9 @@ namespace Kernel
|
||||
return bytes_to_copy;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> FramebufferDevice::ioctl_impl(int cmd, void* arg)
|
||||
BAN::ErrorOr<long> FramebufferDevice::ioctl_impl(unsigned long request, void* arg)
|
||||
{
|
||||
switch (cmd)
|
||||
switch (request)
|
||||
{
|
||||
case FB_MSYNC_RECTANGLE:
|
||||
{
|
||||
@@ -152,7 +152,7 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
return CharacterDevice::ioctl(cmd, arg);
|
||||
return CharacterDevice::ioctl_impl(request, arg);
|
||||
}
|
||||
|
||||
uint32_t FramebufferDevice::get_pixel(uint32_t x, uint32_t y) const
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
namespace Kernel::ELF
|
||||
{
|
||||
@@ -291,7 +290,9 @@ namespace Kernel::ELF
|
||||
TRY(memory_regions.emplace_back(BAN::move(region)));
|
||||
}
|
||||
|
||||
result.open_execfd = !interpreter.empty();
|
||||
if (!interpreter.empty())
|
||||
result.interp_base = load_base_vaddr;
|
||||
|
||||
result.entry_point = load_base_vaddr + file_header.e_entry;
|
||||
result.regions = BAN::move(memory_regions);
|
||||
return BAN::move(result);
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace Kernel
|
||||
[](void* _devfs)
|
||||
{
|
||||
auto* devfs = static_cast<DevFileSystem*>(_devfs);
|
||||
uint64_t next_update_ms = SystemTimer::get().ms_since_boot();
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
@@ -57,7 +58,8 @@ namespace Kernel
|
||||
for (auto& device : devfs->m_devices)
|
||||
device->update();
|
||||
}
|
||||
SystemTimer::get().sleep_ms(10);
|
||||
SystemTimer::get().sleep_until_ms(next_update_ms);
|
||||
next_update_ms += 10;
|
||||
}
|
||||
}, s_instance
|
||||
));
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace Kernel
|
||||
}
|
||||
return block_from_indirect_block_no_lock(block, data_block_index, i + 1, allocate);
|
||||
}
|
||||
data_block_index -= indices_per_block;
|
||||
data_block_index -= depth_block_count;
|
||||
depth_block_count *= indices_per_block;
|
||||
}
|
||||
|
||||
@@ -917,6 +917,8 @@ needs_new_block:
|
||||
auto inode_location = TRY(m_fs.locate_inode(ino()));
|
||||
auto block_buffer = TRY(m_fs.get_block_buffer());
|
||||
|
||||
// FIXME: race condition when syncing multiple inodes :)
|
||||
|
||||
TRY(m_fs.read_block(inode_location.block, block_buffer));
|
||||
if (memcmp(block_buffer.data() + inode_location.offset, &inode, sizeof(Ext2::Inode)))
|
||||
{
|
||||
|
||||
@@ -316,7 +316,7 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Inode::ioctl(int request, void* arg)
|
||||
BAN::ErrorOr<long> Inode::ioctl(unsigned long request, void* arg)
|
||||
{
|
||||
auto ret = ioctl_impl(request, arg);
|
||||
if (!ret.is_error() || ret.error().get_error_code() != ENOTSUP)
|
||||
|
||||
@@ -16,12 +16,13 @@ namespace Kernel
|
||||
|
||||
TRY(inode->link_inode(*inode, "."_sv));
|
||||
TRY(inode->link_inode(static_cast<TmpInode&>(*fs.root_inode()), ".."_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_meminfo, fs, 0400)), "meminfo"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_meminfo, fs, 0444)), "meminfo"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_cmdline, fs, 0444)), "cmdline"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_environ, fs, 0400)), "environ"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_cputime, fs, 0444)), "cputime"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcSymlinkProcessInode::create_new(process, &Process::proc_cwd, fs, 0777)), "cwd"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcSymlinkProcessInode::create_new(process, &Process::proc_exe, fs, 0777)), "exe"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcFDDirectoryInode::create_new(process, fs, 0777)), "fd"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcFDDirectoryInode::create_new(process, fs, 0500)), "fd"_sv));
|
||||
|
||||
return inode;
|
||||
}
|
||||
@@ -38,6 +39,7 @@ namespace Kernel
|
||||
(void)TmpDirectoryInode::unlink_impl("meminfo"_sv);
|
||||
(void)TmpDirectoryInode::unlink_impl("cmdline"_sv);
|
||||
(void)TmpDirectoryInode::unlink_impl("environ"_sv);
|
||||
(void)TmpDirectoryInode::unlink_impl("cputime"_sv);
|
||||
(void)TmpDirectoryInode::unlink_impl("cwd"_sv);
|
||||
(void)TmpDirectoryInode::unlink_impl("exe"_sv);
|
||||
(void)TmpDirectoryInode::unlink_impl("fd"_sv);
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace Kernel
|
||||
if (i == 4)
|
||||
dwarnln("Could not find specified root device, waiting for it to get loaded...");
|
||||
|
||||
SystemTimer::get().sleep_ms(sleep_ms);
|
||||
SystemTimer::get().sleep_for_ms(sleep_ms);
|
||||
}
|
||||
|
||||
derrorln("Could not find root device '{}' after {} ms", root_path, timeout_ms);
|
||||
|
||||
@@ -24,11 +24,6 @@ namespace Kernel
|
||||
#if ARCH(x86_64)
|
||||
struct Registers
|
||||
{
|
||||
uint64_t cr4;
|
||||
uint64_t cr3;
|
||||
uint64_t cr2;
|
||||
uint64_t cr0;
|
||||
|
||||
uint64_t r15;
|
||||
uint64_t r14;
|
||||
uint64_t r13;
|
||||
@@ -49,11 +44,6 @@ namespace Kernel
|
||||
#elif ARCH(i686)
|
||||
struct Registers
|
||||
{
|
||||
uint32_t cr4;
|
||||
uint32_t cr3;
|
||||
uint32_t cr2;
|
||||
uint32_t cr0;
|
||||
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t ebp;
|
||||
@@ -226,8 +216,11 @@ namespace Kernel
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t cr2;
|
||||
asm volatile("mov %%cr2, %0" : "=r"(cr2));
|
||||
|
||||
Processor::set_interrupt_state(InterruptState::Enabled);
|
||||
auto result = Process::current().allocate_page_for_demand_paging(regs->cr2, page_fault_error.write, page_fault_error.instruction);
|
||||
auto result = Process::current().allocate_page_for_demand_paging(cr2, page_fault_error.write, page_fault_error.instruction);
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
if (result.is_error())
|
||||
@@ -286,6 +279,15 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t cr0, cr2, cr3, cr4;
|
||||
asm volatile(
|
||||
"mov %%cr0, %0;"
|
||||
"mov %%cr2, %1;"
|
||||
"mov %%cr3, %2;"
|
||||
"mov %%cr4, %3;"
|
||||
: "=r"(cr0), "=r"(cr2), "=r"(cr3), "=r"(cr4)
|
||||
);
|
||||
|
||||
Debug::s_debug_lock.lock();
|
||||
|
||||
if (PageTable::current().get_page_flags(interrupt_stack->ip & PAGE_ADDR_MASK) & PageTable::Flags::Present)
|
||||
@@ -323,7 +325,7 @@ namespace Kernel
|
||||
regs->r8, regs->r9, regs->r10, regs->r11,
|
||||
regs->r12, regs->r13, regs->r14, regs->r15,
|
||||
interrupt_stack->ip, interrupt_stack->flags,
|
||||
regs->cr0, regs->cr2, regs->cr3, regs->cr4
|
||||
cr0, cr2, cr3, cr4
|
||||
);
|
||||
#elif ARCH(i686)
|
||||
dwarnln(
|
||||
@@ -337,7 +339,7 @@ namespace Kernel
|
||||
regs->eax, regs->ebx, regs->ecx, regs->edx,
|
||||
interrupt_stack->sp, regs->ebp, regs->edi, regs->esi,
|
||||
interrupt_stack->ip, interrupt_stack->flags,
|
||||
regs->cr0, regs->cr2, regs->cr3, regs->cr4
|
||||
cr0, cr2, cr3, cr4
|
||||
);
|
||||
#endif
|
||||
if (isr == ISR::PageFault)
|
||||
@@ -385,11 +387,11 @@ namespace Kernel
|
||||
break;
|
||||
case ISR::PageFault:
|
||||
signal_info.si_signo = SIGSEGV;
|
||||
if (PageTable::current().get_page_flags(regs->cr2 & PAGE_ADDR_MASK) & PageTable::Flags::Present)
|
||||
if (PageTable::current().get_page_flags(cr2 & PAGE_ADDR_MASK) & PageTable::Flags::Present)
|
||||
signal_info.si_code = SEGV_ACCERR;
|
||||
else
|
||||
signal_info.si_code = SEGV_MAPERR;
|
||||
signal_info.si_addr = reinterpret_cast<void*>(regs->cr2);
|
||||
signal_info.si_addr = reinterpret_cast<void*>(cr2);
|
||||
break;
|
||||
default:
|
||||
dwarnln("Unhandled exception");
|
||||
@@ -433,7 +435,7 @@ namespace Kernel
|
||||
if (Processor::current_is_bsp())
|
||||
Process::update_alarm_queue();
|
||||
|
||||
Processor::scheduler().timer_interrupt();
|
||||
Processor::scheduler().on_timer_interrupt();
|
||||
}
|
||||
|
||||
extern "C" void cpp_irq_handler(uint32_t irq)
|
||||
|
||||
@@ -151,16 +151,18 @@ namespace Kernel::Input
|
||||
uint16_t toggle_mask = 0;
|
||||
switch (dummy_event.key)
|
||||
{
|
||||
case Key::LeftShift: modifier_mask = KeyModifier::LShift; break;
|
||||
case Key::RightShift: modifier_mask = KeyModifier::RShift; break;
|
||||
case Key::LeftCtrl: modifier_mask = KeyModifier::LCtrl; break;
|
||||
case Key::RightCtrl: modifier_mask = KeyModifier::RCtrl; break;
|
||||
case Key::LeftAlt: modifier_mask = KeyModifier::LAlt; break;
|
||||
case Key::RightAlt: modifier_mask = KeyModifier::RAlt; break;
|
||||
case Key::LeftShift: modifier_mask = KeyModifier::LShift; break;
|
||||
case Key::RightShift: modifier_mask = KeyModifier::RShift; break;
|
||||
case Key::LeftCtrl: modifier_mask = KeyModifier::LCtrl; break;
|
||||
case Key::RightCtrl: modifier_mask = KeyModifier::RCtrl; break;
|
||||
case Key::LeftAlt: modifier_mask = KeyModifier::LAlt; break;
|
||||
case Key::RightAlt: modifier_mask = KeyModifier::RAlt; break;
|
||||
case Key::LeftSuper: modifier_mask = KeyModifier::LSuper; break;
|
||||
case Key::RightSuper: modifier_mask = KeyModifier::RSuper; break;
|
||||
|
||||
case Key::ScrollLock: toggle_mask = KeyModifier::ScrollLock; break;
|
||||
case Key::NumLock: toggle_mask = KeyModifier::NumLock; break;
|
||||
case Key::CapsLock: toggle_mask = KeyModifier::CapsLock; break;
|
||||
case Key::ScrollLock: toggle_mask = KeyModifier::ScrollLock; break;
|
||||
case Key::NumLock: toggle_mask = KeyModifier::NumLock; break;
|
||||
case Key::CapsLock: toggle_mask = KeyModifier::CapsLock; break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,9 @@ namespace Kernel::Input
|
||||
m_scancode_to_keycode_normal[0x38] = keycode_normal(4, 2);
|
||||
m_scancode_to_keycode_normal[0x39] = keycode_normal(4, 3);
|
||||
m_scancode_to_keycode_extended[0x38] = keycode_normal(4, 4);
|
||||
m_scancode_to_keycode_extended[0x1D] = keycode_normal(4, 5);
|
||||
m_scancode_to_keycode_extended[0x5C] = keycode_normal(4, 5);
|
||||
m_scancode_to_keycode_extended[0x5D] = keycode_normal(4, 6);
|
||||
m_scancode_to_keycode_extended[0x1D] = keycode_normal(4, 7);
|
||||
|
||||
m_scancode_to_keycode_normal[0x45] = keycode_numpad(0, 0);
|
||||
m_scancode_to_keycode_extended[0x35] = keycode_numpad(0, 1);
|
||||
@@ -208,7 +210,9 @@ namespace Kernel::Input
|
||||
m_scancode_to_keycode_normal[0x11] = keycode_normal(4, 2);
|
||||
m_scancode_to_keycode_normal[0x29] = keycode_normal(4, 3);
|
||||
m_scancode_to_keycode_extended[0x11] = keycode_normal(4, 4);
|
||||
m_scancode_to_keycode_extended[0x14] = keycode_normal(4, 5);
|
||||
m_scancode_to_keycode_extended[0x27] = keycode_normal(4, 5);
|
||||
m_scancode_to_keycode_extended[0x2F] = keycode_normal(4, 6);
|
||||
m_scancode_to_keycode_extended[0x14] = keycode_normal(4, 7);
|
||||
|
||||
m_scancode_to_keycode_normal[0x77] = keycode_numpad(0, 0);
|
||||
m_scancode_to_keycode_extended[0x4A] = keycode_numpad(0, 1);
|
||||
@@ -321,7 +325,9 @@ namespace Kernel::Input
|
||||
m_scancode_to_keycode_normal[0x19] = keycode_normal(4, 2);
|
||||
m_scancode_to_keycode_normal[0x29] = keycode_normal(4, 3);
|
||||
m_scancode_to_keycode_normal[0x39] = keycode_normal(4, 4);
|
||||
m_scancode_to_keycode_normal[0x58] = keycode_normal(4, 5);
|
||||
m_scancode_to_keycode_normal[0x8C] = keycode_normal(4, 5);
|
||||
m_scancode_to_keycode_normal[0x8D] = keycode_normal(4, 6);
|
||||
m_scancode_to_keycode_normal[0x58] = keycode_normal(4, 7);
|
||||
|
||||
m_scancode_to_keycode_normal[0x76] = keycode_numpad(0, 0);
|
||||
m_scancode_to_keycode_normal[0x4A] = keycode_numpad(0, 1);
|
||||
|
||||
@@ -112,8 +112,8 @@ namespace Kernel
|
||||
paddr = Heap::get().take_free_page();
|
||||
if (paddr == 0)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
PageTable::with_fast_page(paddr, [&] {
|
||||
memset(PageTable::fast_page_as_ptr(), 0x00, PAGE_SIZE);
|
||||
PageTable::with_per_cpu_fast_page(paddr, [&](void* addr) {
|
||||
memset(addr, 0x00, PAGE_SIZE);
|
||||
});
|
||||
m_object->paddrs[(vaddr - m_vaddr) / PAGE_SIZE] = paddr;
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ namespace Kernel
|
||||
Reply = 2,
|
||||
};
|
||||
|
||||
static constexpr BAN::IPv4Address s_broadcast_ipv4 { 0xFFFFFFFF };
|
||||
static constexpr BAN::MACAddress s_broadcast_mac {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
|
||||
static constexpr BAN::IPv4Address s_broadcast_ipv4 { 0xFFFFFFFF };
|
||||
static constexpr BAN::MACAddress s_broadcast_mac {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<ARPTable>> ARPTable::create()
|
||||
{
|
||||
@@ -50,18 +50,19 @@ namespace Kernel
|
||||
return it->value;
|
||||
}
|
||||
|
||||
ARPPacket arp_request;
|
||||
arp_request.htype = 0x0001;
|
||||
arp_request.ptype = EtherType::IPv4;
|
||||
arp_request.hlen = 0x06;
|
||||
arp_request.plen = 0x04;
|
||||
arp_request.oper = ARPOperation::Request;
|
||||
arp_request.sha = interface.get_mac_address();
|
||||
arp_request.spa = interface.get_ipv4_address();
|
||||
arp_request.tha = {{ 0, 0, 0, 0, 0, 0 }};
|
||||
arp_request.tpa = ipv4_address;
|
||||
const auto arp_request = ARPPacket {
|
||||
.htype = 0x0001,
|
||||
.ptype = EtherType::IPv4,
|
||||
.hlen = 0x06,
|
||||
.plen = 0x04,
|
||||
.oper = ARPOperation::Request,
|
||||
.sha = interface.get_mac_address(),
|
||||
.spa = interface.get_ipv4_address(),
|
||||
.tha = {{ 0, 0, 0, 0, 0, 0 }},
|
||||
.tpa = ipv4_address,
|
||||
};
|
||||
|
||||
TRY(interface.send_bytes(s_broadcast_mac, EtherType::ARP, BAN::ConstByteSpan::from(arp_request)));
|
||||
TRY(interface.send_with_ethernet_header(s_broadcast_mac, EtherType::ARP, BAN::ConstByteSpan::from(arp_request)));
|
||||
|
||||
uint64_t timeout = SystemTimer::get().ms_since_boot() + 1'000;
|
||||
while (SystemTimer::get().ms_since_boot() < timeout)
|
||||
@@ -100,7 +101,7 @@ namespace Kernel
|
||||
{
|
||||
if (packet.tpa == interface.get_ipv4_address())
|
||||
{
|
||||
const ARPPacket arp_reply {
|
||||
const auto arp_reply = ARPPacket {
|
||||
.htype = 0x0001,
|
||||
.ptype = EtherType::IPv4,
|
||||
.hlen = 0x06,
|
||||
@@ -111,7 +112,7 @@ namespace Kernel
|
||||
.tha = packet.sha,
|
||||
.tpa = packet.spa,
|
||||
};
|
||||
TRY(interface.send_bytes(packet.sha, EtherType::ARP, BAN::ConstByteSpan::from(arp_reply)));
|
||||
TRY(interface.send_with_ethernet_header(packet.sha, EtherType::ARP, BAN::ConstByteSpan::from(arp_reply)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -202,6 +202,8 @@ namespace Kernel
|
||||
rctrl |= RCTL_BSIZE_8192;
|
||||
write32(REG_RCTL, rctrl);
|
||||
|
||||
write32(REG_RXCSUM, RXSUM_IPOFLD | RXSUM_TUOFLD);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -279,9 +281,13 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> E1000::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload)
|
||||
BAN::ErrorOr<void> E1000::send_raw_bytes(BAN::Span<const BAN::ConstByteSpan> buffers)
|
||||
{
|
||||
const uint32_t tx_current = m_tx_head1.fetch_add(1) % E1000_TX_DESCRIPTOR_COUNT;
|
||||
const auto interrupt_state = Processor::get_interrupt_state();
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
const uint32_t tx_current_nowrap = m_tx_head.fetch_add(1);
|
||||
const uint32_t tx_current = tx_current_nowrap % E1000_TX_DESCRIPTOR_COUNT;
|
||||
|
||||
auto& descriptor = reinterpret_cast<volatile e1000_tx_desc*>(m_tx_descriptor_region->vaddr())[tx_current];
|
||||
while (descriptor.status == 0)
|
||||
@@ -289,15 +295,10 @@ namespace Kernel
|
||||
|
||||
auto* tx_buffer = reinterpret_cast<uint8_t*>(m_tx_buffer_region->vaddr() + E1000_TX_BUFFER_SIZE * tx_current);
|
||||
|
||||
auto& ethernet_header = *reinterpret_cast<EthernetHeader*>(tx_buffer);
|
||||
ethernet_header.dst_mac = destination;
|
||||
ethernet_header.src_mac = get_mac_address();
|
||||
ethernet_header.ether_type = protocol;
|
||||
|
||||
size_t packet_size = sizeof(EthernetHeader);
|
||||
for (const auto& buffer : payload)
|
||||
size_t packet_size = 0;
|
||||
for (const auto& buffer : buffers)
|
||||
{
|
||||
ASSERT(packet_size + buffer.size() < E1000_TX_BUFFER_SIZE);
|
||||
ASSERT(packet_size + buffer.size() <= E1000_TX_BUFFER_SIZE);
|
||||
memcpy(tx_buffer + packet_size, buffer.data(), buffer.size());
|
||||
packet_size += buffer.size();
|
||||
}
|
||||
@@ -306,8 +307,12 @@ namespace Kernel
|
||||
descriptor.status = 0;
|
||||
descriptor.cmd = CMD_EOP | CMD_IFCS | CMD_RS;
|
||||
|
||||
if (tx_current == m_tx_head2.fetch_add(1) % E1000_TX_DESCRIPTOR_COUNT)
|
||||
write32(REG_TDT, (tx_current + 1) % E1000_TX_DESCRIPTOR_COUNT);
|
||||
while (tx_current_nowrap != m_tx_commit.load())
|
||||
Processor::pause();
|
||||
write32(REG_TDT, (tx_current + 1) % E1000_TX_DESCRIPTOR_COUNT);
|
||||
m_tx_commit.add_fetch(1);
|
||||
|
||||
Processor::set_interrupt_state(interrupt_state);
|
||||
|
||||
dprintln_if(DEBUG_E1000, "sent {} bytes", packet_size);
|
||||
|
||||
@@ -316,35 +321,66 @@ namespace Kernel
|
||||
|
||||
void E1000::receive_thread()
|
||||
{
|
||||
SpinLockGuard _(m_rx_lock);
|
||||
SpinLockGuard guard(m_rx_lock);
|
||||
|
||||
uint32_t rx_current = 0;
|
||||
|
||||
while (!m_thread_should_die)
|
||||
{
|
||||
uint32_t rx_tail = rx_current;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const uint32_t rx_current = (read32(REG_RDT0) + 1) % E1000_RX_DESCRIPTOR_COUNT;
|
||||
|
||||
auto& descriptor = reinterpret_cast<volatile e1000_rx_desc*>(m_rx_descriptor_region->vaddr())[rx_current];
|
||||
if (!(descriptor.status & 1))
|
||||
|
||||
const auto status = descriptor.status;
|
||||
if (!(status & RX_STS_DD))
|
||||
break;
|
||||
ASSERT(descriptor.length <= E1000_RX_BUFFER_SIZE);
|
||||
|
||||
dprintln_if(DEBUG_E1000, "got {} bytes", (uint16_t)descriptor.length);
|
||||
const auto errors = descriptor.errors;
|
||||
if (!(status & RX_STS_EOP))
|
||||
dwarnln("multi descriptor packet??");
|
||||
else if (errors & (RX_ERR_CE | RX_ERR_SE | RX_ERR_RXE))
|
||||
dwarnln("descriptor error {2h}", errors);
|
||||
else if ((status & RX_STS_IPCS) && (errors & RX_ERR_IPE))
|
||||
dwarnln("IPv4 checksum error");
|
||||
else if ((status & RX_STS_TCPCS) && (errors & RX_ERR_TCPE))
|
||||
dwarnln("TCP checkum error");
|
||||
else if ((status & RX_STS_UDPCS) && (errors & RX_ERR_TCPE))
|
||||
dwarnln("UDP checksum error");
|
||||
else
|
||||
{
|
||||
m_rx_lock.unlock(InterruptState::Enabled);
|
||||
|
||||
m_rx_lock.unlock(InterruptState::Enabled);
|
||||
const uint32_t packet_length = descriptor.length;
|
||||
ASSERT(packet_length <= E1000_RX_BUFFER_SIZE);
|
||||
|
||||
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
|
||||
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE),
|
||||
descriptor.length
|
||||
});
|
||||
dprintln_if(DEBUG_E1000, "got {} bytes", packet_length);
|
||||
|
||||
m_rx_lock.lock();
|
||||
uint32_t validated_cksums = 0;
|
||||
if ((status & RX_STS_IPCS) && !(errors & RX_ERR_IPE))
|
||||
validated_cksums |= CKSUM_IPV4;
|
||||
if ((status & RX_STS_TCPCS) && !(errors & RX_ERR_TCPE))
|
||||
validated_cksums |= CKSUM_TCP;
|
||||
if ((status & RX_STS_UDPCS) && !(errors & RX_ERR_TCPE))
|
||||
validated_cksums |= CKSUM_UDP;
|
||||
|
||||
const uint8_t* packet_data = reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE);
|
||||
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { packet_data, packet_length }, validated_cksums);
|
||||
|
||||
m_rx_lock.lock();
|
||||
}
|
||||
|
||||
descriptor.status = 0;
|
||||
write32(REG_RDT0, rx_current);
|
||||
|
||||
rx_tail = rx_current;
|
||||
rx_current = (rx_current + 1) % E1000_RX_DESCRIPTOR_COUNT;
|
||||
}
|
||||
|
||||
SpinLockAsMutex smutex(m_rx_lock, InterruptState::Enabled);
|
||||
if (rx_current != rx_tail)
|
||||
write32(REG_RDT0, rx_tail);
|
||||
|
||||
SpinLockGuardAsMutex smutex(guard);
|
||||
m_rx_blocker.block_indefinite(&smutex);
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> IPv4Layer::sendto(NetworkSocket& socket, BAN::ConstByteSpan payload, const sockaddr* address, socklen_t address_len)
|
||||
BAN::ErrorOr<void> IPv4Layer::sendto(NetworkSocket& socket, BAN::ConstByteSpan payload, const sockaddr* address, socklen_t address_len)
|
||||
{
|
||||
if (address->sa_family != AF_INET)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
@@ -224,23 +224,21 @@ namespace Kernel
|
||||
};
|
||||
|
||||
uint8_t protocol_header_buffer[32];
|
||||
ASSERT(socket.protocol_header_size() < sizeof(protocol_header_buffer));
|
||||
|
||||
auto protocol_header = BAN::ByteSpan::from(protocol_header_buffer).slice(0, socket.protocol_header_size());
|
||||
socket.get_protocol_header(protocol_header, payload, dst_port, pseudo_header);
|
||||
|
||||
BAN::ConstByteSpan buffers[] {
|
||||
const BAN::ConstByteSpan buffers[] {
|
||||
BAN::ConstByteSpan::from(ipv4_header),
|
||||
protocol_header,
|
||||
payload,
|
||||
};
|
||||
|
||||
TRY(interface->send_bytes(dst_mac, EtherType::IPv4, { buffers, sizeof(buffers) / sizeof(*buffers) }));
|
||||
TRY(interface->send_with_ethernet_header(dst_mac, EtherType::IPv4, buffers));
|
||||
|
||||
return payload.size();
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> IPv4Layer::handle_ipv4_packet(NetworkInterface& interface, BAN::ConstByteSpan packet)
|
||||
BAN::ErrorOr<void> IPv4Layer::handle_ipv4_packet(NetworkInterface& interface, BAN::ConstByteSpan packet, uint32_t validated_cksums)
|
||||
{
|
||||
if (packet.size() < sizeof(IPv4Header))
|
||||
{
|
||||
@@ -249,7 +247,7 @@ namespace Kernel
|
||||
}
|
||||
|
||||
auto& ipv4_header = packet.as<const IPv4Header>();
|
||||
if (calculate_internet_checksum(BAN::ConstByteSpan::from(ipv4_header)) != 0)
|
||||
if (!(validated_cksums & CKSUM_IPV4) && calculate_internet_checksum(BAN::ConstByteSpan::from(ipv4_header)) != 0)
|
||||
{
|
||||
dwarnln_if(DEBUG_IPV4, "IPv4 packet checksum failed");
|
||||
return {};
|
||||
@@ -284,34 +282,33 @@ namespace Kernel
|
||||
{
|
||||
case ICMPType::EchoRequest:
|
||||
{
|
||||
auto dst_mac = TRY(m_arp_table->get_mac_from_ipv4(interface, src_ipv4));
|
||||
const auto dst_mac = TRY(m_arp_table->get_mac_from_ipv4(interface, src_ipv4));
|
||||
|
||||
auto send_ipv4_header = get_ipv4_header(
|
||||
const auto send_ipv4_header = get_ipv4_header(
|
||||
ipv4_data.size(),
|
||||
interface.get_ipv4_address(),
|
||||
src_ipv4,
|
||||
NetworkProtocol::ICMP
|
||||
);
|
||||
|
||||
ICMPHeader send_icmp_header {
|
||||
auto send_icmp_header = ICMPHeader {
|
||||
.type = ICMPType::EchoReply,
|
||||
.code = icmp_header.code,
|
||||
.checksum = 0,
|
||||
.rest = icmp_header.rest,
|
||||
};
|
||||
|
||||
auto send_payload = ipv4_data.slice(sizeof(ICMPHeader));
|
||||
|
||||
const BAN::ConstByteSpan send_buffers[] {
|
||||
BAN::ConstByteSpan::from(send_ipv4_header),
|
||||
BAN::ConstByteSpan::from(send_icmp_header),
|
||||
send_payload
|
||||
ipv4_data.slice(sizeof(ICMPHeader))
|
||||
};
|
||||
auto send_buffers_span = BAN::Span { send_buffers, sizeof(send_buffers) / sizeof(*send_buffers) };
|
||||
|
||||
send_icmp_header.checksum = calculate_internet_checksum(send_buffers_span.slice(1));
|
||||
send_icmp_header.checksum = calculate_internet_checksum({
|
||||
send_buffers + 1, sizeof(send_buffers) / sizeof(*send_buffers) - 1
|
||||
});
|
||||
|
||||
TRY(interface.send_bytes(dst_mac, EtherType::IPv4, send_buffers_span));
|
||||
TRY(interface.send_with_ethernet_header(dst_mac, EtherType::IPv4, send_buffers));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -389,7 +386,7 @@ namespace Kernel
|
||||
sender.sin_family = AF_INET;
|
||||
sender.sin_port = BAN::host_to_network_endian(src_port);
|
||||
sender.sin_addr.s_addr = src_ipv4.raw;
|
||||
bound_socket->receive_packet(ipv4_data, reinterpret_cast<const sockaddr*>(&sender), sizeof(sender));
|
||||
bound_socket->receive_packet(ipv4_data, reinterpret_cast<const sockaddr*>(&sender), sizeof(sender), validated_cksums);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Lock/SpinLockAsMutex.h>
|
||||
#include <kernel/Networking/Loopback.h>
|
||||
#include <kernel/Networking/NetworkManager.h>
|
||||
|
||||
@@ -54,12 +54,15 @@ namespace Kernel
|
||||
Processor::yield();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> LoopbackInterface::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload)
|
||||
BAN::ErrorOr<void> LoopbackInterface::send_raw_bytes(BAN::Span<const BAN::ConstByteSpan> buffers)
|
||||
{
|
||||
const auto interrupt_state = Processor::get_interrupt_state();
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
auto& descriptor =
|
||||
[&]() -> Descriptor&
|
||||
{
|
||||
LockGuard _(m_buffer_lock);
|
||||
SpinLockGuard guard(m_buffer_lock);
|
||||
for (;;)
|
||||
{
|
||||
auto& descriptor = m_descriptors[m_buffer_head];
|
||||
@@ -69,34 +72,31 @@ namespace Kernel
|
||||
descriptor.state = 1;
|
||||
return descriptor;
|
||||
}
|
||||
m_thread_blocker.block_indefinite(&m_buffer_lock);
|
||||
SpinLockGuardAsMutex smutex(guard);
|
||||
m_thread_blocker.block_indefinite(&smutex);
|
||||
}
|
||||
}();
|
||||
|
||||
auto& ethernet_header = *reinterpret_cast<EthernetHeader*>(descriptor.addr);
|
||||
ethernet_header.dst_mac = destination;
|
||||
ethernet_header.src_mac = get_mac_address();
|
||||
ethernet_header.ether_type = protocol;
|
||||
|
||||
size_t packet_size = sizeof(EthernetHeader);
|
||||
for (const auto& buffer : payload)
|
||||
size_t packet_size = 0;
|
||||
for (const auto& buffer : buffers)
|
||||
{
|
||||
ASSERT(packet_size + buffer.size() <= buffer_size);
|
||||
memcpy(descriptor.addr + packet_size, buffer.data(), buffer.size());
|
||||
packet_size += buffer.size();
|
||||
}
|
||||
|
||||
LockGuard _(m_buffer_lock);
|
||||
m_buffer_lock.lock();
|
||||
descriptor.size = packet_size;
|
||||
descriptor.state = 2;
|
||||
m_thread_blocker.unblock();
|
||||
m_buffer_lock.unlock(interrupt_state);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void LoopbackInterface::receive_thread()
|
||||
{
|
||||
LockGuard _(m_buffer_lock);
|
||||
SpinLockGuard guard(m_buffer_lock);
|
||||
|
||||
while (!m_thread_should_die)
|
||||
{
|
||||
@@ -107,12 +107,9 @@ namespace Kernel
|
||||
break;
|
||||
m_buffer_tail = (m_buffer_tail + 1) % buffer_count;
|
||||
|
||||
m_buffer_lock.unlock();
|
||||
m_buffer_lock.unlock(InterruptState::Enabled);
|
||||
|
||||
NetworkManager::get().on_receive(*this, {
|
||||
descriptor.addr,
|
||||
descriptor.size,
|
||||
});
|
||||
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { descriptor.addr, descriptor.size }, 0);
|
||||
|
||||
m_buffer_lock.lock();
|
||||
|
||||
@@ -121,7 +118,8 @@ namespace Kernel
|
||||
m_thread_blocker.unblock();
|
||||
}
|
||||
|
||||
m_thread_blocker.block_indefinite(&m_buffer_lock);
|
||||
SpinLockGuardAsMutex smutex(guard);
|
||||
m_thread_blocker.block_indefinite(&smutex);
|
||||
}
|
||||
|
||||
m_thread_is_dead = true;
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> NetworkInterface::ioctl_impl(int request, void* arg)
|
||||
BAN::ErrorOr<long> NetworkInterface::ioctl_impl(unsigned long request, void* arg)
|
||||
{
|
||||
if (arg == nullptr)
|
||||
{
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
void NetworkManager::on_receive(NetworkInterface& interface, BAN::ConstByteSpan packet)
|
||||
void NetworkManager::on_receive(NetworkInterface& interface, BAN::ConstByteSpan packet, uint32_t validated_cksums)
|
||||
{
|
||||
if (packet.size() < sizeof(EthernetHeader))
|
||||
return;
|
||||
@@ -163,7 +163,7 @@ namespace Kernel
|
||||
dwarnln("ARP: {}", ret.error());
|
||||
break;
|
||||
case EtherType::IPv4:
|
||||
if (auto ret = m_ipv4_layer->handle_ipv4_packet(interface, packet_data); ret.is_error())
|
||||
if (auto ret = m_ipv4_layer->handle_ipv4_packet(interface, packet_data, validated_cksums); ret.is_error())
|
||||
dwarnln("IPv4; {}", ret.error());
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace Kernel
|
||||
m_address_len = addr_len;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> NetworkSocket::ioctl_impl(int request, void* arg)
|
||||
BAN::ErrorOr<long> NetworkSocket::ioctl_impl(unsigned long request, void* arg)
|
||||
{
|
||||
switch (request)
|
||||
{
|
||||
|
||||
@@ -47,30 +47,29 @@ namespace Kernel
|
||||
|
||||
TRY(reset());
|
||||
|
||||
// disable rx, tx, checksum offload
|
||||
m_io_bar_region->write16(RTL8169_IO_CPlusCR, 0x0000);
|
||||
m_io_bar_region->write8 (RTL8169_IO_CR, 0x00);
|
||||
|
||||
dprintln(" reset done");
|
||||
|
||||
for (size_t i = 0; i < 6; i++)
|
||||
m_mac_address.address[i] = m_io_bar_region->read8(RTL8169_IO_IDR0 + i);
|
||||
dprintln(" MAC {}", m_mac_address);
|
||||
|
||||
// unlock config registers
|
||||
m_io_bar_region->write8(RTL8169_IO_9346CR, RTL8169_9346CR_MODE_CONFIG);
|
||||
|
||||
TRY(initialize_rx());
|
||||
TRY(initialize_tx());
|
||||
m_io_bar_region->write8(RTL8169_IO_CR, RTL8169_CR_RE | RTL8169_CR_TE);
|
||||
dprintln(" descriptors initialized");
|
||||
|
||||
m_link_up = m_io_bar_region->read8(RTL8169_IO_PHYSts) & RTL8169_PHYSts_LinkSts;
|
||||
if (m_link_up)
|
||||
dprintln(" link status {}", link_up() ? "UP" : "DOWN");
|
||||
if (link_up())
|
||||
dprintln(" link speed {}", link_speed());
|
||||
|
||||
TRY(enable_interrupt());
|
||||
dprintln(" interrupts enabled");
|
||||
|
||||
// lock config registers
|
||||
m_io_bar_region->write8(RTL8169_IO_9346CR, RTL8169_9346CR_MODE_NORMAL);
|
||||
|
||||
auto* thread = TRY(Thread::create_kernel([](void* rtl8169_ptr) {
|
||||
static_cast<RTL8169*>(rtl8169_ptr)->receive_thread();
|
||||
}, this));
|
||||
@@ -79,17 +78,17 @@ namespace Kernel
|
||||
delete thread;
|
||||
return ret.release_error();
|
||||
}
|
||||
m_thread_is_dead = false;
|
||||
m_rx_thread_is_dead = false;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
RTL8169::~RTL8169()
|
||||
{
|
||||
m_thread_should_die = true;
|
||||
m_thread_blocker.unblock();
|
||||
m_rx_thread_should_die = true;
|
||||
m_rx_blocker.unblock();
|
||||
|
||||
while (!m_thread_is_dead)
|
||||
while (!m_rx_thread_is_dead)
|
||||
Processor::yield();
|
||||
}
|
||||
|
||||
@@ -110,35 +109,33 @@ namespace Kernel
|
||||
m_rx_buffer_region = TRY(DMARegion::create(m_rx_descriptor_count * s_buffer_size, PageTable::MemoryType::Normal));
|
||||
m_rx_descriptor_region = TRY(DMARegion::create(m_rx_descriptor_count * sizeof(RTL8169Descriptor)));
|
||||
|
||||
auto* rx_descriptors = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr());
|
||||
for (size_t i = 0; i < m_rx_descriptor_count; i++)
|
||||
{
|
||||
const paddr_t rx_buffer_paddr = m_rx_buffer_region->paddr() + i * s_buffer_size;
|
||||
|
||||
uint32_t command = 0x1FF8 | RTL8169_DESC_CMD_OWN;
|
||||
if (i == m_rx_descriptor_count - 1)
|
||||
command |= RTL8169_DESC_CMD_EOR;
|
||||
|
||||
auto& rx_descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr())[i];
|
||||
rx_descriptor.command = command;
|
||||
rx_descriptor.vlan = 0;
|
||||
rx_descriptor.buffer_low = rx_buffer_paddr & 0xFFFFFFFF;
|
||||
rx_descriptor.buffer_high = rx_buffer_paddr >> 32;
|
||||
rx_descriptors[i].command = 0x1FF8 | RTL8169_DESC_CMD_OWN;
|
||||
rx_descriptors[i].vlan = 0;
|
||||
rx_descriptors[i].buffer_low = rx_buffer_paddr & 0xFFFFFFFF;
|
||||
rx_descriptors[i].buffer_high = rx_buffer_paddr >> 32;
|
||||
}
|
||||
rx_descriptors[m_rx_descriptor_count - 1].command |= RTL8169_DESC_CMD_EOR;
|
||||
|
||||
// configure rx descriptor addresses
|
||||
m_io_bar_region->write32(RTL8169_IO_RDSAR + 0, m_rx_descriptor_region->paddr() & 0xFFFFFFFF);
|
||||
m_io_bar_region->write32(RTL8169_IO_RDSAR + 4, m_rx_descriptor_region->paddr() >> 32);
|
||||
m_io_bar_region->write32(RTL8169_IO_RDSAR + 0, m_rx_descriptor_region->paddr() & 0xFFFFFFFF);
|
||||
|
||||
// configure receibe control (no fifo threshold, max dma burst 1024, accept physical match, broadcast, multicast)
|
||||
// configure receive control (no fifo threshold, max dma burst unlimited, broadcast, multicast, accept physical match)
|
||||
m_io_bar_region->write32(RTL8169_IO_RCR,
|
||||
RTL8169_RCR_RXFTH_NO | RTL8169_RCR_MXDMA_1024 | RTL8169_RCR_AB | RTL8169_RCR_AM | RTL8169_RCR_APM
|
||||
RTL8169_RCR_RXFTH_NO | RTL8169_RCR_MXDMA_UNLIMITED | RTL8169_RCR_AB | RTL8169_RCR_AM | RTL8169_RCR_APM
|
||||
);
|
||||
|
||||
m_io_bar_region->write32(0x44, 0b111111 | (0b111 << 8) | (0b111 << 13));
|
||||
|
||||
// configure max rx packet size
|
||||
m_io_bar_region->write16(RTL8169_IO_RMS, RTL8169_RMS_MAX);
|
||||
|
||||
// enable ip/tcp/udp checksum offloading
|
||||
// TODO: is this supported on all cards?
|
||||
m_io_bar_region->write16(RTL8169_IO_CPlusCR, 1 << 5);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -147,27 +144,23 @@ namespace Kernel
|
||||
m_tx_buffer_region = TRY(DMARegion::create(m_tx_descriptor_count * s_buffer_size, PageTable::MemoryType::Normal));
|
||||
m_tx_descriptor_region = TRY(DMARegion::create(m_tx_descriptor_count * sizeof(RTL8169Descriptor)));
|
||||
|
||||
auto* tx_descriptors = reinterpret_cast<volatile RTL8169Descriptor*>(m_tx_descriptor_region->vaddr());
|
||||
for (size_t i = 0; i < m_tx_descriptor_count; i++)
|
||||
{
|
||||
const paddr_t tx_buffer_paddr = m_tx_buffer_region->paddr() + i * s_buffer_size;
|
||||
|
||||
uint32_t command = 0;
|
||||
if (i == m_tx_descriptor_count - 1)
|
||||
command |= RTL8169_DESC_CMD_EOR;
|
||||
|
||||
auto& tx_descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_tx_descriptor_region->vaddr())[i];
|
||||
tx_descriptor.command = command;
|
||||
tx_descriptor.vlan = 0;
|
||||
tx_descriptor.buffer_low = tx_buffer_paddr & 0xFFFFFFFF;
|
||||
tx_descriptor.buffer_high = tx_buffer_paddr >> 32;
|
||||
tx_descriptors[i].command = 0;
|
||||
tx_descriptors[i].vlan = 0;
|
||||
tx_descriptors[i].buffer_low = tx_buffer_paddr & 0xFFFFFFFF;
|
||||
tx_descriptors[i].buffer_high = tx_buffer_paddr >> 32;
|
||||
}
|
||||
tx_descriptors[m_tx_descriptor_count - 1].command |= RTL8169_DESC_CMD_EOR;
|
||||
|
||||
// configure tx descriptor addresses
|
||||
m_io_bar_region->write32(RTL8169_IO_TNPDS + 0, m_tx_descriptor_region->paddr() & 0xFFFFFFFF);
|
||||
m_io_bar_region->write32(RTL8169_IO_TNPDS + 4, m_tx_descriptor_region->paddr() >> 32);
|
||||
m_io_bar_region->write32(RTL8169_IO_TNPDS + 0, m_tx_descriptor_region->paddr() & 0xFFFFFFFF);
|
||||
|
||||
// configure transmit control (standard ifg, max dma burst 1024)
|
||||
m_io_bar_region->write32(RTL8169_IO_TCR, RTL8169_TCR_IFG_0 | RTL8169_TCR_MXDMA_1024);
|
||||
// configure transmit control (standard ifg, max dma burst unlimited)
|
||||
m_io_bar_region->write32(RTL8169_IO_TCR, RTL8169_TCR_IFG_0 | RTL8169_TCR_MXDMA_UNLIMITED);
|
||||
|
||||
// configure max tx packet size
|
||||
m_io_bar_region->write8(RTL8169_IO_MTPS, RTL8169_MTPS_MAX);
|
||||
@@ -181,14 +174,13 @@ namespace Kernel
|
||||
m_pci_device.enable_interrupt(0, *this);
|
||||
|
||||
m_io_bar_region->write16(RTL8169_IO_IMR,
|
||||
RTL8169_IR_ROK
|
||||
| RTL8169_IR_RER
|
||||
| RTL8169_IR_TOK
|
||||
| RTL8169_IR_TER
|
||||
| RTL8169_IR_RDU
|
||||
| RTL8169_IR_LinkChg
|
||||
| RTL8169_IR_FVOW
|
||||
| RTL8169_IR_TDU
|
||||
RTL8169_IR_ROK |
|
||||
RTL8169_IR_RER |
|
||||
RTL8169_IR_TOK |
|
||||
RTL8169_IR_TER |
|
||||
RTL8169_IR_RDU |
|
||||
RTL8169_IR_LinkChg |
|
||||
RTL8169_IR_FVOW
|
||||
);
|
||||
m_io_bar_region->write16(RTL8169_IO_ISR, 0xFFFF);
|
||||
|
||||
@@ -209,122 +201,156 @@ namespace Kernel
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> RTL8169::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload)
|
||||
BAN::ErrorOr<void> RTL8169::send_raw_bytes(BAN::Span<const BAN::ConstByteSpan> buffers)
|
||||
{
|
||||
if (!link_up())
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
|
||||
auto state = m_lock.lock();
|
||||
const auto interrupt_state = Processor::get_interrupt_state();
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
const uint32_t tx_current = m_tx_current;
|
||||
m_tx_current = (m_tx_current + 1) % m_tx_descriptor_count;
|
||||
const uint32_t tx_current_nowrap = m_tx_head.fetch_add(1);
|
||||
const uint32_t tx_current = tx_current_nowrap % m_tx_descriptor_count;
|
||||
|
||||
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_tx_descriptor_region->vaddr())[tx_current];
|
||||
while (descriptor.command & RTL8169_DESC_CMD_OWN)
|
||||
if (descriptor.command & RTL8169_DESC_CMD_OWN)
|
||||
{
|
||||
SpinLockAsMutex smutex(m_lock, state);
|
||||
m_thread_blocker.block_indefinite(&smutex);
|
||||
SpinLockGuard guard(m_tx_lock);
|
||||
while (descriptor.command & RTL8169_DESC_CMD_OWN)
|
||||
{
|
||||
SpinLockGuardAsMutex smutex(guard);
|
||||
m_tx_blocker.block_indefinite(&smutex);
|
||||
}
|
||||
}
|
||||
|
||||
m_lock.unlock(state);
|
||||
|
||||
auto* tx_buffer = reinterpret_cast<uint8_t*>(m_tx_buffer_region->vaddr() + tx_current * s_buffer_size);
|
||||
|
||||
// write packet
|
||||
auto& ethernet_header = *reinterpret_cast<EthernetHeader*>(tx_buffer);
|
||||
ethernet_header.dst_mac = destination;
|
||||
ethernet_header.src_mac = get_mac_address();
|
||||
ethernet_header.ether_type = protocol;
|
||||
|
||||
size_t packet_size = sizeof(EthernetHeader);
|
||||
for (const auto& buffer : payload)
|
||||
size_t packet_size = 0;
|
||||
for (const auto& buffer : buffers)
|
||||
{
|
||||
ASSERT(packet_size + buffer.size() <= s_buffer_size);
|
||||
memcpy(tx_buffer + packet_size, buffer.data(), buffer.size());
|
||||
packet_size += buffer.size();
|
||||
}
|
||||
|
||||
// give packet ownership to NIC
|
||||
uint32_t command = packet_size | RTL8169_DESC_CMD_OWN | RTL8169_DESC_CMD_LS | RTL8169_DESC_CMD_FS;
|
||||
if (tx_current >= m_tx_descriptor_count - 1)
|
||||
if (tx_current == m_tx_descriptor_count - 1)
|
||||
command |= RTL8169_DESC_CMD_EOR;
|
||||
descriptor.command = command;
|
||||
|
||||
// notify NIC about new packet
|
||||
m_io_bar_region->write8(RTL8169_IO_TPPoll, RTL8169_TPPoll_NPQ);
|
||||
// ring tx queue doorbell
|
||||
if (tx_current_nowrap == m_tx_commit.load())
|
||||
m_io_bar_region->write8(RTL8169_IO_TPPoll, RTL8169_TPPoll_NPQ);
|
||||
while (tx_current_nowrap != m_tx_commit.load())
|
||||
Processor::pause();
|
||||
m_tx_commit.add_fetch(1);
|
||||
|
||||
Processor::set_interrupt_state(interrupt_state);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void RTL8169::receive_thread()
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
SpinLockGuard rx_lock_guard(m_rx_lock);
|
||||
|
||||
while (!m_thread_should_die)
|
||||
while (!m_rx_thread_should_die)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr())[m_rx_current];
|
||||
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr())[m_rx_head];
|
||||
|
||||
const auto command = descriptor.command;
|
||||
if (descriptor.command & RTL8169_DESC_CMD_OWN)
|
||||
break;
|
||||
|
||||
// packet buffer can only hold single packet, so we should not receive any multi-descriptor packets
|
||||
ASSERT((descriptor.command & RTL8169_DESC_CMD_LS) && (descriptor.command & RTL8169_DESC_CMD_FS));
|
||||
ASSERT((command & RTL8169_DESC_CMD_LS) && (command & RTL8169_DESC_CMD_FS));
|
||||
|
||||
const uint16_t packet_length = descriptor.command & 0x3FFF;
|
||||
const uint8_t protocol = (command >> 17) & 3;
|
||||
const uint16_t packet_length = command & 0x3FFF;
|
||||
if (packet_length > s_buffer_size)
|
||||
dwarnln("Got {} bytes to {} byte buffer", packet_length, s_buffer_size);
|
||||
else if (descriptor.command & (1u << 21))
|
||||
; // descriptor has an error
|
||||
else if (command & (1u << 21))
|
||||
dwarnln("descriptor error {4h}", command);
|
||||
else if (protocol == 1 && (command & (1u << 14)))
|
||||
dwarnln("TCP checksum error");
|
||||
else if (protocol == 2 && (command & (1u << 15)))
|
||||
dwarnln("UDP checksum error");
|
||||
else if (protocol != 0 && (command & (1u << 16)))
|
||||
dwarnln("IPv4 checksum error");
|
||||
else
|
||||
{
|
||||
m_lock.unlock(InterruptState::Enabled);
|
||||
m_rx_lock.unlock(InterruptState::Enabled);
|
||||
|
||||
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
|
||||
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + m_rx_current * s_buffer_size),
|
||||
packet_length
|
||||
});
|
||||
uint32_t validated_cksums;
|
||||
switch (protocol)
|
||||
{
|
||||
case 0: validated_cksums = 0; break;
|
||||
case 1: validated_cksums = CKSUM_IPV4 | CKSUM_TCP; break;
|
||||
case 2: validated_cksums = CKSUM_IPV4 | CKSUM_UDP; break;
|
||||
case 3: validated_cksums = CKSUM_IPV4; break;
|
||||
}
|
||||
|
||||
m_lock.lock();
|
||||
const uint8_t* packet_data = reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + m_rx_head * s_buffer_size);
|
||||
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { packet_data, packet_length }, validated_cksums);
|
||||
|
||||
m_rx_lock.lock();
|
||||
}
|
||||
|
||||
m_rx_current = (m_rx_current + 1) % m_rx_descriptor_count;
|
||||
uint32_t new_command = 0x1FF8 | RTL8169_DESC_CMD_OWN;
|
||||
if (m_rx_head == m_rx_descriptor_count - 1)
|
||||
new_command |= RTL8169_DESC_CMD_EOR;
|
||||
descriptor.command = new_command;
|
||||
|
||||
descriptor.command = descriptor.command | RTL8169_DESC_CMD_OWN;
|
||||
m_rx_head = (m_rx_head + 1) % m_rx_descriptor_count;
|
||||
}
|
||||
|
||||
SpinLockAsMutex smutex(m_lock, InterruptState::Enabled);
|
||||
m_thread_blocker.block_indefinite(&smutex);
|
||||
SpinLockGuardAsMutex smutex(rx_lock_guard);
|
||||
m_rx_blocker.block_indefinite(&smutex);
|
||||
}
|
||||
|
||||
m_thread_is_dead = true;
|
||||
m_rx_thread_is_dead = true;
|
||||
}
|
||||
|
||||
void RTL8169::handle_irq()
|
||||
{
|
||||
const uint16_t interrupt_status = m_io_bar_region->read16(RTL8169_IO_ISR);
|
||||
m_io_bar_region->write16(RTL8169_IO_ISR, interrupt_status);
|
||||
|
||||
if (interrupt_status & RTL8169_IR_LinkChg)
|
||||
uint16_t isr;
|
||||
while ((isr = m_io_bar_region->read16(RTL8169_IO_ISR)))
|
||||
{
|
||||
m_link_up = m_io_bar_region->read8(RTL8169_IO_PHYSts) & RTL8169_PHYSts_LinkSts;
|
||||
dprintln("link status -> {}", m_link_up.load());
|
||||
}
|
||||
m_io_bar_region->write16(RTL8169_IO_ISR, isr);
|
||||
|
||||
if (interrupt_status & (RTL8169_IR_TOK | RTL8169_IR_ROK))
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
m_thread_blocker.unblock();
|
||||
}
|
||||
if (isr & RTL8169_IR_LinkChg)
|
||||
{
|
||||
m_link_up = m_io_bar_region->read8(RTL8169_IO_PHYSts) & RTL8169_PHYSts_LinkSts;
|
||||
dprintln("link status {}", link_up() ? "UP" : "DOWN");
|
||||
if (link_up())
|
||||
dprintln("link speed {}", link_speed());
|
||||
}
|
||||
|
||||
if (interrupt_status & RTL8169_IR_RER)
|
||||
dwarnln("Rx error");
|
||||
if (interrupt_status & RTL8169_IR_TER)
|
||||
dwarnln("Tx error");
|
||||
if (interrupt_status & RTL8169_IR_RDU)
|
||||
dwarnln("Rx descriptor not available");
|
||||
if (interrupt_status & RTL8169_IR_FVOW)
|
||||
dwarnln("Rx FIFO overflow");
|
||||
// dont log TDU is sent after each sent packet
|
||||
if (isr & (RTL8169_IR_TER | RTL8169_IR_TOK))
|
||||
{
|
||||
SpinLockGuard _(m_tx_lock);
|
||||
m_tx_blocker.unblock();
|
||||
}
|
||||
|
||||
if (isr & (RTL8169_IR_RER | RTL8169_IR_ROK))
|
||||
{
|
||||
SpinLockGuard _(m_rx_lock);
|
||||
m_rx_blocker.unblock();
|
||||
}
|
||||
|
||||
if (isr & RTL8169_IR_RER)
|
||||
dwarnln("Rx error");
|
||||
if (isr & RTL8169_IR_TER)
|
||||
dwarnln("Tx error");
|
||||
if (isr & RTL8169_IR_RDU)
|
||||
dwarnln("Rx descriptor not available");
|
||||
if (isr & RTL8169_IR_FVOW)
|
||||
dwarnln("Rx FIFO overflow");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -402,7 +402,7 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> TCPSocket::ioctl_impl(int request, void* argument)
|
||||
BAN::ErrorOr<long> TCPSocket::ioctl_impl(unsigned long request, void* argument)
|
||||
{
|
||||
switch (request)
|
||||
{
|
||||
@@ -572,7 +572,7 @@ namespace Kernel
|
||||
dprintln_if(DEBUG_TCP, " seq {}", (uint32_t)header.seq_number);
|
||||
}
|
||||
|
||||
void TCPSocket::receive_packet(BAN::ConstByteSpan buffer, const sockaddr* sender, socklen_t sender_len)
|
||||
void TCPSocket::receive_packet(BAN::ConstByteSpan packet, const sockaddr* sender, socklen_t sender_len, uint32_t validated_cksums)
|
||||
{
|
||||
if (m_state == State::Listen)
|
||||
{
|
||||
@@ -585,9 +585,10 @@ namespace Kernel
|
||||
}();
|
||||
|
||||
if (socket)
|
||||
return socket->receive_packet(buffer, sender, sender_len);
|
||||
return socket->receive_packet(packet, sender, sender_len, validated_cksums);
|
||||
}
|
||||
|
||||
if (!(validated_cksums & CKSUM_TCP))
|
||||
{
|
||||
uint16_t checksum = 0;
|
||||
|
||||
@@ -603,23 +604,23 @@ namespace Kernel
|
||||
.src_ipv4 = BAN::IPv4Address(addr_in.sin_addr.s_addr),
|
||||
.dst_ipv4 = interface->get_ipv4_address(),
|
||||
.protocol = NetworkProtocol::TCP,
|
||||
.length = buffer.size(),
|
||||
.length = packet.size(),
|
||||
};
|
||||
const BAN::ConstByteSpan buffers[] {
|
||||
BAN::ConstByteSpan::from(pseudo_header),
|
||||
buffer
|
||||
packet
|
||||
};
|
||||
checksum = calculate_internet_checksum({ buffers, sizeof(buffers) / sizeof(*buffers) });
|
||||
}
|
||||
else
|
||||
{
|
||||
dwarnln("No tcp checksum validation for socket family {}", sender->sa_family);
|
||||
dwarnln("no TCP checksum validation for socket family {}", sender->sa_family);
|
||||
return;
|
||||
}
|
||||
|
||||
if (checksum != 0)
|
||||
{
|
||||
dprintln("Checksum does not match");
|
||||
dwarnln("checksum does not match");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -628,7 +629,7 @@ namespace Kernel
|
||||
|
||||
const bool hungup_before = has_hungup_impl();
|
||||
|
||||
auto& header = buffer.as<const TCPHeader>();
|
||||
const auto& header = packet.as<const TCPHeader>();
|
||||
|
||||
dprintln_if(DEBUG_TCP, "receiving {} {8b}", (uint8_t)m_state, header.flags);
|
||||
dprintln_if(DEBUG_TCP, " ack {}", (uint32_t)header.ack_number);
|
||||
@@ -768,7 +769,7 @@ namespace Kernel
|
||||
if (header.ack_number > m_send_window.current_ack)
|
||||
m_send_window.current_ack = header.ack_number;
|
||||
|
||||
auto payload = buffer.slice(header.data_offset * sizeof(uint32_t));
|
||||
auto payload = packet.slice(header.data_offset * sizeof(uint32_t));
|
||||
|
||||
if (header.seq_number < expected_seq)
|
||||
{
|
||||
@@ -967,6 +968,9 @@ namespace Kernel
|
||||
if (m_last_sent_window_size == 0)
|
||||
m_should_send_zero_window = false;
|
||||
|
||||
if (m_last_sent_window_size == m_recv_window.buffer->free())
|
||||
m_should_send_window_update = false;
|
||||
|
||||
if (m_should_send_zero_window || m_should_send_window_update)
|
||||
{
|
||||
ASSERT(m_connection_info.has_value());
|
||||
|
||||
@@ -57,21 +57,69 @@ namespace Kernel
|
||||
header.checksum = 0xFFFF;
|
||||
}
|
||||
|
||||
void UDPSocket::receive_packet(BAN::ConstByteSpan packet, const sockaddr* sender, socklen_t sender_len)
|
||||
void UDPSocket::receive_packet(BAN::ConstByteSpan packet, const sockaddr* sender, socklen_t sender_len, uint32_t validated_cksums)
|
||||
{
|
||||
auto payload = packet.slice(sizeof(UDPHeader));
|
||||
const auto header = packet.as<const UDPHeader>();
|
||||
|
||||
if (!(validated_cksums & CKSUM_UDP) && header.checksum)
|
||||
{
|
||||
uint16_t checksum = 0;
|
||||
|
||||
if (sender->sa_family == AF_INET)
|
||||
{
|
||||
auto interface_or_error = interface(sender, sender_len);
|
||||
if (interface_or_error.is_error())
|
||||
return;
|
||||
auto interface = interface_or_error.release_value();
|
||||
|
||||
auto& addr_in = *reinterpret_cast<const sockaddr_in*>(sender);
|
||||
const PseudoHeader pseudo_header {
|
||||
.src_ipv4 = BAN::IPv4Address(addr_in.sin_addr.s_addr),
|
||||
.dst_ipv4 = interface->get_ipv4_address(),
|
||||
.protocol = NetworkProtocol::UDP,
|
||||
.length = packet.size(),
|
||||
};
|
||||
const UDPHeader udp_header {
|
||||
.src_port = header.src_port,
|
||||
.dst_port = header.dst_port,
|
||||
.length = header.length,
|
||||
.checksum = 0,
|
||||
};
|
||||
const BAN::ConstByteSpan buffers[] {
|
||||
BAN::ConstByteSpan::from(pseudo_header),
|
||||
BAN::ConstByteSpan::from(udp_header),
|
||||
packet.slice(sizeof(UDPHeader))
|
||||
};
|
||||
checksum = calculate_internet_checksum({ buffers, sizeof(buffers) / sizeof(*buffers) });
|
||||
}
|
||||
else
|
||||
{
|
||||
dwarnln("no UDP checksum validation for socket family {}", sender->sa_family);
|
||||
return;
|
||||
}
|
||||
|
||||
const bool checksum_valid1 = (header.checksum == checksum);
|
||||
const bool checksum_valid2 = (header.checksum == 0xFFFF && checksum == 0);
|
||||
if (!checksum_valid1 && !checksum_valid2)
|
||||
{
|
||||
dwarnln("checksum does not match {4h}", checksum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SpinLockGuard _(m_packet_lock);
|
||||
|
||||
if (m_packets.full())
|
||||
{
|
||||
dprintln("Packet buffer full, dropping packet");
|
||||
dwarnln("Packet buffer full, dropping packet");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto payload = packet.slice(sizeof(UDPHeader));
|
||||
|
||||
if (m_packet_total_size + payload.size() > m_packet_buffer->size())
|
||||
{
|
||||
dprintln("Packet buffer full, dropping packet");
|
||||
dwarnln("Packet buffer full, dropping packet");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -224,7 +272,9 @@ namespace Kernel
|
||||
address_len = message.msg_namelen;
|
||||
}
|
||||
|
||||
return TRY(m_network_layer.sendto(*this, buffer.span(), address, address_len));
|
||||
TRY(m_network_layer.sendto(*this, buffer.span(), address, address_len));
|
||||
|
||||
return buffer.size();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> UDPSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len)
|
||||
@@ -286,7 +336,7 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> UDPSocket::ioctl_impl(int request, void* argument)
|
||||
BAN::ErrorOr<long> UDPSocket::ioctl_impl(unsigned long request, void* argument)
|
||||
{
|
||||
switch (request)
|
||||
{
|
||||
|
||||
@@ -704,6 +704,25 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> UnixDomainSocket::getsockname_impl(sockaddr* address, socklen_t* address_len)
|
||||
{
|
||||
sockaddr_un sa_un {
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = {},
|
||||
};
|
||||
|
||||
{
|
||||
LockGuard _(m_bind_mutex);
|
||||
strcpy(sa_un.sun_path, m_bound_file.canonical_path.data());
|
||||
}
|
||||
|
||||
const size_t to_copy = BAN::Math::min<socklen_t>(sizeof(sockaddr_un), *address_len);
|
||||
memcpy(address, &sa_un, to_copy);
|
||||
*address_len = to_copy;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
BAN::ErrorOr<void> UnixDomainSocket::getpeername_impl(sockaddr* address, socklen_t* address_len)
|
||||
{
|
||||
if (!m_info.has<ConnectionInfo>())
|
||||
@@ -713,20 +732,7 @@ namespace Kernel
|
||||
if (!connection)
|
||||
return BAN::Error::from_errno(ENOTCONN);
|
||||
|
||||
sockaddr_un sa_un {
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = {},
|
||||
};
|
||||
|
||||
{
|
||||
LockGuard _(m_bind_mutex);
|
||||
strcpy(sa_un.sun_path, connection->m_bound_file.canonical_path.data());
|
||||
}
|
||||
|
||||
const size_t to_copy = BAN::Math::min<socklen_t>(sizeof(sockaddr_un), *address_len);
|
||||
memcpy(address, &sa_un, to_copy);
|
||||
*address_len = to_copy;
|
||||
return {};
|
||||
return connection->getsockname_impl(address, address_len);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> UnixDomainSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len)
|
||||
@@ -743,12 +749,24 @@ namespace Kernel
|
||||
case SO_ERROR:
|
||||
result = 0;
|
||||
break;
|
||||
case SO_KEEPALIVE:
|
||||
result = 1;
|
||||
break;
|
||||
case SO_SNDBUF:
|
||||
result = m_sndbuf;
|
||||
break;
|
||||
case SO_RCVBUF:
|
||||
result = m_packet_buffer->size();
|
||||
break;
|
||||
case SO_TYPE:
|
||||
switch (m_socket_type)
|
||||
{
|
||||
case Type::STREAM: result = SOCK_STREAM; break;
|
||||
case Type::DGRAM: result = SOCK_DGRAM; break;
|
||||
case Type::SEQPACKET: result = SOCK_SEQPACKET; break;
|
||||
default: ASSERT_NOT_REACHED();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dwarnln("getsockopt(SOL_SOCKET, {})", option);
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
|
||||
@@ -401,11 +401,19 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<void> OpenFileDescriptorSet::close(int fd)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
BAN::RefPtr<OpenFileDescription> open_file;
|
||||
|
||||
TRY(validate_fd(fd));
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
auto& open_file = m_open_files[fd];
|
||||
TRY(validate_fd(fd));
|
||||
|
||||
open_file = m_open_files[fd];
|
||||
|
||||
m_open_files[fd]->file.inode->on_close(m_open_files[fd]->status_flags);
|
||||
m_open_files[fd] = {};
|
||||
remove_cloexec(fd);
|
||||
}
|
||||
|
||||
if (auto& flock = open_file->flock; Thread::current().has_process() && flock.lockers.contains(Process::current().pid()))
|
||||
{
|
||||
@@ -429,10 +437,6 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
open_file->file.inode->on_close(open_file->status_flags);
|
||||
open_file = {};
|
||||
remove_cloexec(fd);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -235,11 +235,13 @@ namespace Kernel::PCI
|
||||
switch (pci_device.subclass())
|
||||
{
|
||||
case 0x01:
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
if (auto res = ATAController::create(pci_device); res.is_error())
|
||||
dprintln("ATA: {}", res.error());
|
||||
break;
|
||||
case 0x06:
|
||||
if (auto res = AHCIController::create(pci_device); res.is_error())
|
||||
dprintln("AHCI: {}", res.error());
|
||||
break;
|
||||
case 0x08:
|
||||
if (auto res = NVMeController::create(pci_device); res.is_error())
|
||||
dprintln("NVMe: {}", res.error());
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include <LibInput/KeyboardLayout.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/banan-os.h>
|
||||
#include <sys/eventfd.h>
|
||||
@@ -98,25 +97,19 @@ namespace Kernel
|
||||
return process;
|
||||
}
|
||||
|
||||
void Process::register_to_scheduler()
|
||||
{
|
||||
// FIXME: Allow failing...
|
||||
{
|
||||
SpinLockGuard _(s_process_lock);
|
||||
MUST(s_processes.push_back(this));
|
||||
}
|
||||
for (auto* thread : m_threads)
|
||||
MUST(Processor::scheduler().add_thread(thread));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Process*> Process::create_userspace(const Credentials& credentials, BAN::StringView path, BAN::Span<BAN::StringView> arguments)
|
||||
{
|
||||
auto* process = create_process(credentials, 0);
|
||||
BAN::ScopeGuard process_deleter([process] {
|
||||
process->m_mapped_regions.clear();
|
||||
process->m_page_table.clear();
|
||||
delete process;
|
||||
});
|
||||
|
||||
process->m_working_directory = VirtualFileSystem::get().root_file();
|
||||
process->m_root_file = VirtualFileSystem::get().root_file();
|
||||
|
||||
process->m_page_table = BAN::UniqPtr<PageTable>::adopt(MUST(PageTable::create_userspace()));
|
||||
process->m_page_table = BAN::UniqPtr<PageTable>::adopt(TRY(PageTable::create_userspace()));
|
||||
|
||||
TRY(process->m_cmdline.emplace_back());
|
||||
TRY(process->m_cmdline.back().append(path));
|
||||
@@ -126,14 +119,12 @@ namespace Kernel
|
||||
TRY(process->m_cmdline.back().append(argument));
|
||||
}
|
||||
|
||||
LockGuard _(process->m_process_lock);
|
||||
|
||||
auto executable_file = TRY(process->find_file(AT_FDCWD, path.data(), O_EXEC));
|
||||
auto executable_inode = executable_file.inode;
|
||||
|
||||
auto executable = TRY(ELF::load_from_inode(process->m_root_file.inode, executable_inode, process->m_credentials, process->page_table()));
|
||||
for (auto& region : executable.regions)
|
||||
TRY(process->add_mapped_region(BAN::move(region)));
|
||||
TRY(process->m_mapped_regions.push_back(BAN::move(region)));
|
||||
executable.regions.clear();
|
||||
|
||||
TRY(process->m_executable.append(executable_file.canonical_path));
|
||||
@@ -143,19 +134,7 @@ namespace Kernel
|
||||
if (executable_inode->mode().mode & +Inode::Mode::ISGID)
|
||||
process->m_credentials.set_egid(executable_inode->gid());
|
||||
|
||||
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
|
||||
TRY(auxiliary_vector.reserve(1 + executable.open_execfd));
|
||||
|
||||
if (executable.open_execfd)
|
||||
{
|
||||
const int execfd = TRY(process->m_open_file_descriptors.open(BAN::move(executable_file), O_RDONLY));
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_EXECFD,
|
||||
.a_un = { .a_val = static_cast<uint32_t>(execfd) },
|
||||
}));
|
||||
}
|
||||
|
||||
process->m_shared_page_vaddr = process->page_table().reserve_free_page(process->m_mapped_regions.back()->vaddr(), USERSPACE_END);
|
||||
process->m_shared_page_vaddr = process->page_table().reserve_free_page(executable.interp_base.value_or(0x400000), USERSPACE_END);
|
||||
if (process->m_shared_page_vaddr == 0)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
process->page_table().map_page_at(
|
||||
@@ -164,31 +143,89 @@ namespace Kernel
|
||||
PageTable::UserSupervisor | PageTable::Present
|
||||
);
|
||||
|
||||
auto userspace_stack = TRY(MemoryBackedRegion::create(
|
||||
process->page_table(),
|
||||
Thread::userspace_stack_size,
|
||||
{ Thread::userspace_stack_base, USERSPACE_END },
|
||||
MemoryRegion::Type::PRIVATE,
|
||||
PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present,
|
||||
O_RDWR
|
||||
));
|
||||
|
||||
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
|
||||
TRY(auxiliary_vector.reserve(5 + 2 * executable.interp_base.has_value()));
|
||||
|
||||
if (executable.interp_base.has_value())
|
||||
{
|
||||
const int execfd = TRY(process->m_open_file_descriptors.open(BAN::move(executable_file), O_RDONLY));
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_EXECFD,
|
||||
.a_un = { .a_val = static_cast<uint32_t>(execfd) },
|
||||
}));
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_BASE,
|
||||
.a_un = { .a_ptr = reinterpret_cast<void*>(executable.interp_base.value()) },
|
||||
}));
|
||||
}
|
||||
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_PAGESZ,
|
||||
.a_un = { .a_val = PAGE_SIZE },
|
||||
}));
|
||||
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_SHARED_PAGE,
|
||||
.a_un = { .a_ptr = reinterpret_cast<void*>(process->m_shared_page_vaddr) },
|
||||
}));
|
||||
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_STACK_BASE,
|
||||
.a_un = { .a_ptr = reinterpret_cast<void*>(userspace_stack->vaddr()) },
|
||||
}));
|
||||
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_STACK_SIZE,
|
||||
.a_un = { .a_ptr = reinterpret_cast<void*>(userspace_stack->size()) },
|
||||
}));
|
||||
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_NULL,
|
||||
.a_un = { .a_val = 0 },
|
||||
}));
|
||||
|
||||
BAN::Optional<vaddr_t> tls_addr;
|
||||
if (executable.master_tls.has_value())
|
||||
{
|
||||
auto tls_result = TRY(process->initialize_thread_local_storage(process->page_table(), *executable.master_tls));
|
||||
TRY(process->add_mapped_region(BAN::move(tls_result.region)));
|
||||
tls_addr = tls_result.addr;
|
||||
}
|
||||
|
||||
auto* thread = MUST(Thread::create_userspace(process, process->page_table()));
|
||||
MUST(thread->initialize_userspace(
|
||||
executable.entry_point,
|
||||
const vaddr_t initial_stack_pointer = TRY(process->setup_initial_process_stack(
|
||||
*userspace_stack,
|
||||
process->m_cmdline.span(),
|
||||
process->m_environ.span(),
|
||||
auxiliary_vector.span()
|
||||
));
|
||||
|
||||
const vaddr_t userspace_stack_vaddr = userspace_stack->vaddr();
|
||||
const vaddr_t userspace_stack_size = userspace_stack->size();
|
||||
TRY(process->m_mapped_regions.push_back(BAN::move(userspace_stack)));
|
||||
|
||||
BAN::Optional<vaddr_t> tls_addr;
|
||||
if (executable.master_tls.has_value())
|
||||
{
|
||||
auto tls_result = TRY(process->initialize_thread_local_storage(process->page_table(), *executable.master_tls));
|
||||
TRY(process->m_mapped_regions.push_back(BAN::move(tls_result.region)));
|
||||
tls_addr = tls_result.addr;
|
||||
}
|
||||
|
||||
BAN::sort::sort(process->m_mapped_regions.begin(), process->m_mapped_regions.end(), [](const auto& a, const auto& b) {
|
||||
return a->vaddr() < b->vaddr();
|
||||
});
|
||||
|
||||
auto* thread = TRY(Thread::create_userspace(
|
||||
process,
|
||||
process->page_table(),
|
||||
userspace_stack_vaddr,
|
||||
userspace_stack_size,
|
||||
executable.entry_point,
|
||||
initial_stack_pointer
|
||||
));
|
||||
BAN::ScopeGuard thread_deleter([thread] { delete thread; });
|
||||
|
||||
if (tls_addr.has_value())
|
||||
{
|
||||
#if ARCH(x86_64)
|
||||
@@ -200,11 +237,118 @@ namespace Kernel
|
||||
#endif
|
||||
}
|
||||
|
||||
process->add_thread(thread);
|
||||
process->register_to_scheduler();
|
||||
// NOTE: make sure the last two `MUST`s don't fail
|
||||
TRY(process->m_threads.reserve(1));
|
||||
TRY(Processor::scheduler().bind_thread_to_processor(thread, Processor::current_id()));
|
||||
|
||||
{
|
||||
SpinLockGuard _(s_process_lock);
|
||||
TRY(s_processes.push_back(process));
|
||||
}
|
||||
|
||||
MUST(process->m_threads.push_back(thread));
|
||||
MUST(Processor::scheduler().add_thread(thread));
|
||||
|
||||
process_deleter.disable();
|
||||
thread_deleter.disable();
|
||||
|
||||
return process;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<vaddr_t> Process::setup_initial_process_stack(MemoryBackedRegion& stack_region, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv)
|
||||
{
|
||||
// System V ABI: Initial process stack
|
||||
|
||||
size_t needed_size = 0;
|
||||
|
||||
// argc
|
||||
needed_size += sizeof(uintptr_t);
|
||||
|
||||
// argv
|
||||
needed_size += (argv.size() + 1) * sizeof(uintptr_t);
|
||||
for (auto arg : argv)
|
||||
needed_size += arg.size() + 1;
|
||||
|
||||
// envp
|
||||
needed_size += (envp.size() + 1) * sizeof(uintptr_t);
|
||||
for (auto env : envp)
|
||||
needed_size += env.size() + 1;
|
||||
|
||||
// auxv
|
||||
needed_size += auxv.size() * sizeof(LibELF::AuxiliaryVector);
|
||||
|
||||
if (auto rem = needed_size % alignof(char*))
|
||||
needed_size += alignof(char*) - rem;
|
||||
|
||||
if (needed_size > stack_region.size())
|
||||
return BAN::Error::from_errno(ENOBUFS);
|
||||
|
||||
vaddr_t vaddr = stack_region.vaddr() + stack_region.size() - needed_size;
|
||||
|
||||
const size_t page_count = BAN::Math::div_round_up<size_t>(needed_size, PAGE_SIZE);
|
||||
for (size_t i = 0; i < page_count; i++)
|
||||
TRY(stack_region.allocate_page_containing(vaddr + i * PAGE_SIZE, true));
|
||||
|
||||
const auto stack_copy_buf =
|
||||
[&stack_region](BAN::ConstByteSpan buffer, vaddr_t vaddr) -> void
|
||||
{
|
||||
ASSERT(vaddr >= stack_region.vaddr());
|
||||
ASSERT(vaddr + buffer.size() <= stack_region.vaddr() + stack_region.size());
|
||||
MUST(stack_region.copy_data_to_region(vaddr - stack_region.vaddr(), buffer.data(), buffer.size()));
|
||||
};
|
||||
|
||||
const auto stack_push_buf =
|
||||
[&stack_copy_buf, &vaddr](BAN::ConstByteSpan buffer) -> void
|
||||
{
|
||||
stack_copy_buf(buffer, vaddr);
|
||||
vaddr += buffer.size();
|
||||
};
|
||||
|
||||
const auto stack_push_uint =
|
||||
[&stack_push_buf](uintptr_t value) -> void
|
||||
{
|
||||
stack_push_buf(BAN::ConstByteSpan::from(value));
|
||||
};
|
||||
|
||||
const auto stack_push_str =
|
||||
[&stack_push_buf](BAN::StringView string) -> void
|
||||
{
|
||||
const uint8_t* string_u8 = reinterpret_cast<const uint8_t*>(string.data());
|
||||
stack_push_buf(BAN::ConstByteSpan(string_u8, string.size() + 1));
|
||||
};
|
||||
|
||||
// argc
|
||||
stack_push_uint(argv.size());
|
||||
|
||||
// argv
|
||||
const vaddr_t argv_vaddr = vaddr;
|
||||
vaddr += argv.size() * sizeof(uintptr_t);
|
||||
stack_push_uint(0);
|
||||
|
||||
// envp
|
||||
const vaddr_t envp_vaddr = vaddr;
|
||||
vaddr += envp.size() * sizeof(uintptr_t);
|
||||
stack_push_uint(0);
|
||||
|
||||
// auxv
|
||||
for (auto aux : auxv)
|
||||
stack_push_buf(BAN::ConstByteSpan::from(aux));
|
||||
|
||||
// information
|
||||
for (size_t i = 0; i < argv.size(); i++)
|
||||
{
|
||||
stack_copy_buf(BAN::ConstByteSpan::from(vaddr), argv_vaddr + i * sizeof(uintptr_t));
|
||||
stack_push_str(argv[i]);
|
||||
}
|
||||
for (size_t i = 0; i < envp.size(); i++)
|
||||
{
|
||||
stack_copy_buf(BAN::ConstByteSpan::from(vaddr), envp_vaddr + i * sizeof(uintptr_t));
|
||||
stack_push_str(envp[i]);
|
||||
}
|
||||
|
||||
return stack_region.vaddr() + stack_region.size() - needed_size;
|
||||
}
|
||||
|
||||
Process::Process(const Credentials& credentials, pid_t pid, pid_t parent, pid_t sid, pid_t pgrp)
|
||||
: m_credentials(credentials)
|
||||
, m_open_file_descriptors(m_credentials)
|
||||
@@ -223,7 +367,7 @@ namespace Kernel
|
||||
Process::~Process()
|
||||
{
|
||||
ASSERT(m_threads.empty());
|
||||
ASSERT(m_exited_pthreads.empty());
|
||||
ASSERT(m_exited_threads.empty());
|
||||
ASSERT(m_mapped_regions.empty());
|
||||
ASSERT(!m_page_table);
|
||||
}
|
||||
@@ -245,12 +389,6 @@ namespace Kernel
|
||||
return valid_pgrp;
|
||||
}
|
||||
|
||||
void Process::add_thread(Thread* thread)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
MUST(m_threads.push_back(thread));
|
||||
}
|
||||
|
||||
void Process::cleanup_function(Thread* thread)
|
||||
{
|
||||
{
|
||||
@@ -271,7 +409,7 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
m_exited_pthreads.clear();
|
||||
m_exited_threads.clear();
|
||||
|
||||
ProcFileSystem::get().on_process_delete(*this);
|
||||
|
||||
@@ -283,21 +421,14 @@ namespace Kernel
|
||||
// NOTE: We must unmap ranges while the page table is still alive
|
||||
m_mapped_regions.clear();
|
||||
|
||||
// After we give our page table to the thread, we cannot get rescheduled
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
thread->give_keep_alive_page_table(BAN::move(m_page_table));
|
||||
}
|
||||
|
||||
bool Process::on_thread_exit(Thread& thread)
|
||||
{
|
||||
{
|
||||
RWLockWRGuard _(m_memory_region_lock);
|
||||
|
||||
const size_t index = find_mapped_region(thread.userspace_stack().vaddr());
|
||||
ASSERT(m_mapped_regions[index].ptr() == thread.m_userspace_stack);
|
||||
|
||||
m_mapped_regions.remove(index);
|
||||
|
||||
thread.m_userspace_stack = nullptr;
|
||||
}
|
||||
// TODO: if main thread exists, should we delete its stack?
|
||||
|
||||
LockGuard _(m_process_lock);
|
||||
|
||||
@@ -410,52 +541,41 @@ namespace Kernel
|
||||
O_EXEC | O_RDWR
|
||||
));
|
||||
|
||||
BAN::Vector<uint8_t> temp_buffer;
|
||||
TRY(temp_buffer.resize(BAN::Math::min<size_t>(master_size, PAGE_SIZE)));
|
||||
|
||||
size_t bytes_copied = 0;
|
||||
while (bytes_copied < master_size)
|
||||
{
|
||||
const size_t to_copy = BAN::Math::min(master_size - bytes_copied, temp_buffer.size());
|
||||
uint8_t buffer[PAGE_SIZE];
|
||||
const size_t to_copy = BAN::Math::min(master_size - bytes_copied, sizeof(buffer));
|
||||
|
||||
const vaddr_t vaddr = master_addr + bytes_copied;
|
||||
const paddr_t paddr = page_table.physical_address_of(vaddr & PAGE_ADDR_MASK);
|
||||
PageTable::with_fast_page(paddr, [&] {
|
||||
memcpy(temp_buffer.data(), PageTable::fast_page_as_ptr(vaddr % PAGE_SIZE), to_copy);
|
||||
memcpy(buffer, PageTable::fast_page_as_ptr(vaddr % PAGE_SIZE), to_copy);
|
||||
});
|
||||
|
||||
TRY(region->copy_data_to_region(bytes_copied, temp_buffer.data(), to_copy));
|
||||
TRY(region->copy_data_to_region(bytes_copied, buffer, to_copy));
|
||||
bytes_copied += to_copy;
|
||||
}
|
||||
|
||||
auto uthread = TRY(BAN::UniqPtr<struct uthread>::create());
|
||||
*uthread = {
|
||||
.self = reinterpret_cast<struct uthread*>(region->vaddr() + master_size),
|
||||
.master_tls_addr = reinterpret_cast<void*>(master_addr),
|
||||
.master_tls_size = master_size,
|
||||
.master_tls_module_count = 1,
|
||||
.dynamic_tls = nullptr,
|
||||
.cleanup_stack = nullptr,
|
||||
.id = 0,
|
||||
.errno_ = 0,
|
||||
.cancel_type = 0,
|
||||
.cancel_state = 0,
|
||||
.canceled = 0,
|
||||
.specific_keys = {},
|
||||
.specific_values = {},
|
||||
.dtv = { 0, region->vaddr() }
|
||||
};
|
||||
uthread uthread {};
|
||||
uthread.self = reinterpret_cast<struct uthread*>(region->vaddr() + master_size);
|
||||
uthread.master_tls_addr = reinterpret_cast<void*>(master_addr),
|
||||
uthread.master_tls_size = master_size,
|
||||
uthread.master_tls_module_count = 1;
|
||||
uthread.dynamic_tls = nullptr;
|
||||
uthread.dtv[0] = 0;
|
||||
uthread.dtv[1] = region->vaddr();
|
||||
|
||||
TRY(region->copy_data_to_region(
|
||||
master_size,
|
||||
reinterpret_cast<const uint8_t*>(uthread.ptr()),
|
||||
reinterpret_cast<const uint8_t*>(&uthread),
|
||||
sizeof(struct uthread)
|
||||
));
|
||||
|
||||
TLSResult result;
|
||||
result.addr = region->vaddr() + master_size;;
|
||||
result.region = BAN::move(region);
|
||||
return result;
|
||||
return TLSResult {
|
||||
.region = BAN::move(region),
|
||||
.addr = region->vaddr() + master_size,
|
||||
};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Process::add_mapped_region(BAN::UniqPtr<MemoryRegion>&& region)
|
||||
@@ -574,6 +694,25 @@ namespace Kernel
|
||||
return read_from_vec_of_str(m_environ, offset, buffer);
|
||||
}
|
||||
|
||||
size_t Process::proc_cputime(off_t offset, BAN::ByteSpan buffer) const
|
||||
{
|
||||
const uint64_t cpu_time_ns = [this] {
|
||||
uint64_t cpu_time_ns { 0 };
|
||||
LockGuard _(m_process_lock);
|
||||
for (auto* thread : m_threads)
|
||||
cpu_time_ns += thread->cpu_time_ns();
|
||||
return cpu_time_ns;
|
||||
}();
|
||||
|
||||
auto data = MUST(BAN::String::formatted("{}", cpu_time_ns));
|
||||
if (static_cast<size_t>(offset) >= data.size() + 1)
|
||||
return 0;
|
||||
|
||||
const size_t to_copy = BAN::Math::min<size_t>(data.size() - offset + 1, buffer.size());
|
||||
memcpy(buffer.data(), data.data(), to_copy);
|
||||
return to_copy;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::String> Process::proc_cwd() const
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
@@ -724,13 +863,30 @@ namespace Kernel
|
||||
);
|
||||
|
||||
Process* forked = create_process(m_credentials, m_pid, m_sid, m_pgrp);
|
||||
BAN::ScopeGuard process_deleter([forked] {
|
||||
forked->m_page_table.clear();
|
||||
delete forked;
|
||||
});
|
||||
forked->m_page_table = BAN::move(page_table);
|
||||
|
||||
Thread* thread = TRY(Thread::current().clone(forked, sp, ip));
|
||||
BAN::ScopeGuard thread_deleter([thread] { delete thread; });
|
||||
|
||||
// NOTE: make sure the last two `MUST`s don't fail
|
||||
TRY(forked->m_threads.reserve(1));
|
||||
TRY(Processor::scheduler().bind_thread_to_processor(thread, Processor::current_id()));
|
||||
|
||||
{
|
||||
SpinLockGuard _(s_process_lock);
|
||||
TRY(s_processes.push_back(forked));
|
||||
}
|
||||
|
||||
forked->m_controlling_terminal = m_controlling_terminal;
|
||||
forked->m_working_directory = BAN::move(working_directory);
|
||||
forked->m_root_file = BAN::move(root_file);
|
||||
forked->m_cmdline = BAN::move(cmdline);
|
||||
forked->m_environ = BAN::move(environ);
|
||||
forked->m_executable = BAN::move(executable);
|
||||
forked->m_page_table = BAN::move(page_table);
|
||||
forked->m_shared_page_vaddr = BAN::move(shared_page_vaddr);
|
||||
forked->m_open_file_descriptors = BAN::move(*open_file_descriptors);
|
||||
forked->m_mapped_regions = BAN::move(mapped_regions);
|
||||
@@ -742,10 +898,12 @@ namespace Kernel
|
||||
child_exit_status->pgrp = forked->pgrp();
|
||||
|
||||
ASSERT(this == &Process::current());
|
||||
// FIXME: this should be able to fail
|
||||
Thread* thread = MUST(Thread::current().clone(forked, sp, ip));
|
||||
forked->add_thread(thread);
|
||||
forked->register_to_scheduler();
|
||||
|
||||
MUST(forked->m_threads.push_back(thread));
|
||||
MUST(Processor::scheduler().add_thread(thread));
|
||||
|
||||
process_deleter.disable();
|
||||
thread_deleter.disable();
|
||||
|
||||
return forked->pid();
|
||||
}
|
||||
@@ -801,8 +959,26 @@ namespace Kernel
|
||||
BAN::String executable_path;
|
||||
TRY(executable_path.append(executable_file.canonical_path));
|
||||
|
||||
const vaddr_t shared_page_vaddr = new_page_table->reserve_free_page(executable.interp_base.value_or(0x400000), USERSPACE_END);
|
||||
if (shared_page_vaddr == 0)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
new_page_table->map_page_at(
|
||||
Processor::shared_page_paddr(),
|
||||
shared_page_vaddr,
|
||||
PageTable::UserSupervisor | PageTable::Present
|
||||
);
|
||||
|
||||
auto userspace_stack = TRY(MemoryBackedRegion::create(
|
||||
*new_page_table,
|
||||
Thread::userspace_stack_size,
|
||||
{ Thread::userspace_stack_base, USERSPACE_END },
|
||||
MemoryRegion::Type::PRIVATE,
|
||||
PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present,
|
||||
O_RDWR
|
||||
));
|
||||
|
||||
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
|
||||
TRY(auxiliary_vector.reserve(1 + executable.open_execfd));
|
||||
TRY(auxiliary_vector.reserve(5 + 2 * executable.interp_base.has_value()));
|
||||
|
||||
BAN::ScopeGuard execfd_guard([this, &auxiliary_vector] {
|
||||
if (auxiliary_vector.empty())
|
||||
@@ -812,64 +988,94 @@ namespace Kernel
|
||||
MUST(m_open_file_descriptors.close(auxiliary_vector.front().a_un.a_val));
|
||||
});
|
||||
|
||||
if (executable.open_execfd)
|
||||
if (executable.interp_base.has_value())
|
||||
{
|
||||
const int execfd = TRY(m_open_file_descriptors.open(BAN::move(executable_file), O_RDONLY));
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_EXECFD,
|
||||
.a_un = { .a_val = static_cast<uint32_t>(execfd) },
|
||||
}));
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_BASE,
|
||||
.a_un = { .a_ptr = reinterpret_cast<void*>(executable.interp_base.value()) },
|
||||
}));
|
||||
}
|
||||
|
||||
const vaddr_t shared_page_vaddr = new_page_table->reserve_free_page(new_mapped_regions.back()->vaddr(), USERSPACE_END);
|
||||
if (shared_page_vaddr == 0)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
new_page_table->map_page_at(
|
||||
Processor::shared_page_paddr(),
|
||||
shared_page_vaddr,
|
||||
PageTable::UserSupervisor | PageTable::Present
|
||||
);
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_PAGESZ,
|
||||
.a_un = { .a_val = PAGE_SIZE },
|
||||
}));
|
||||
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_SHARED_PAGE,
|
||||
.a_un = { .a_ptr = reinterpret_cast<void*>(shared_page_vaddr) },
|
||||
}));
|
||||
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_STACK_BASE,
|
||||
.a_un = { .a_ptr = reinterpret_cast<void*>(userspace_stack->vaddr()) },
|
||||
}));
|
||||
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_STACK_SIZE,
|
||||
.a_un = { .a_ptr = reinterpret_cast<void*>(userspace_stack->size()) },
|
||||
}));
|
||||
|
||||
TRY(auxiliary_vector.push_back({
|
||||
.a_type = LibELF::AT_NULL,
|
||||
.a_un = { .a_val = 0 },
|
||||
}));
|
||||
|
||||
// This is ugly but thread insterts userspace stack to process' memory region
|
||||
BAN::swap(m_mapped_regions, new_mapped_regions);
|
||||
auto new_thread_or_error = Thread::create_userspace(this, *new_page_table);
|
||||
BAN::swap(m_mapped_regions, new_mapped_regions);
|
||||
|
||||
auto* new_thread = TRY(new_thread_or_error);
|
||||
TRY(new_thread->initialize_userspace(
|
||||
executable.entry_point,
|
||||
const vaddr_t initial_stack_pointer = TRY(setup_initial_process_stack(
|
||||
*userspace_stack,
|
||||
str_argv.span(),
|
||||
str_envp.span(),
|
||||
auxiliary_vector.span()
|
||||
));
|
||||
|
||||
const vaddr_t userspace_stack_vaddr = userspace_stack->vaddr();
|
||||
const vaddr_t userspace_stack_size = userspace_stack->size();
|
||||
TRY(new_mapped_regions.emplace_back(BAN::move(userspace_stack)));
|
||||
|
||||
BAN::Optional<vaddr_t> tls_addr;
|
||||
if (executable.master_tls.has_value())
|
||||
{
|
||||
auto tls_result = TRY(initialize_thread_local_storage(*new_page_table, *executable.master_tls));
|
||||
TRY(new_mapped_regions.emplace_back(BAN::move(tls_result.region)));
|
||||
#if ARCH(x86_64)
|
||||
new_thread->set_fsbase(tls_result.addr);
|
||||
#elif ARCH(i686)
|
||||
new_thread->set_gsbase(tls_result.addr);
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
tls_addr = tls_result.addr;
|
||||
}
|
||||
|
||||
BAN::sort::sort(new_mapped_regions.begin(), new_mapped_regions.end(), [](auto& a, auto& b) {
|
||||
return a->vaddr() < b->vaddr();
|
||||
});
|
||||
|
||||
auto* new_thread = TRY(Thread::create_userspace(
|
||||
this,
|
||||
*new_page_table,
|
||||
userspace_stack_vaddr,
|
||||
userspace_stack_size,
|
||||
executable.entry_point,
|
||||
initial_stack_pointer
|
||||
));
|
||||
if (tls_addr.has_value())
|
||||
{
|
||||
#if ARCH(x86_64)
|
||||
new_thread->set_fsbase(tls_addr.value());
|
||||
#elif ARCH(i686)
|
||||
new_thread->set_gsbase(tls_addr.value());
|
||||
#else
|
||||
#error
|
||||
#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);
|
||||
|
||||
// NOTE: this is done before disabling interrupts and moving the threads as
|
||||
@@ -880,13 +1086,6 @@ namespace Kernel
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
// NOTE: bind new thread to this processor so it wont be rescheduled before end of this function
|
||||
if (auto ret = Scheduler::bind_thread_to_processor(new_thread, Processor::current_id()); ret.is_error())
|
||||
{
|
||||
Processor::set_interrupt_state(InterruptState::Enabled);
|
||||
return ret.release_error();
|
||||
}
|
||||
|
||||
// after this point, everything is initialized and nothing can fail!
|
||||
|
||||
ASSERT(m_threads.size() == 1);
|
||||
@@ -1009,52 +1208,45 @@ namespace Kernel
|
||||
return child_pid;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_sleep(int seconds)
|
||||
{
|
||||
if (seconds == 0)
|
||||
return 0;
|
||||
|
||||
const uint64_t wake_time_ms = SystemTimer::get().ms_since_boot() + (seconds * 1000);
|
||||
|
||||
while (!Thread::current().is_interrupted_by_signal())
|
||||
{
|
||||
const uint64_t current_ms = SystemTimer::get().ms_since_boot();
|
||||
if (current_ms >= wake_time_ms)
|
||||
break;
|
||||
SystemTimer::get().sleep_ms(wake_time_ms - current_ms);
|
||||
}
|
||||
|
||||
const uint64_t current_ms = SystemTimer::get().ms_since_boot();
|
||||
if (current_ms < wake_time_ms)
|
||||
return BAN::Math::div_round_up<long>(wake_time_ms - current_ms, 1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_nanosleep(const timespec* user_rqtp, timespec* user_rmtp)
|
||||
{
|
||||
// take current timestamp ASAP
|
||||
uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
||||
|
||||
timespec rqtp;
|
||||
TRY(read_from_user(user_rqtp, &rqtp, sizeof(timespec)));
|
||||
|
||||
if (rqtp.tv_nsec < 0 || rqtp.tv_nsec >= 1'000'000'000)
|
||||
if (rqtp.tv_sec < 0 || rqtp.tv_nsec < 0 || rqtp.tv_nsec >= 1'000'000'000)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
const uint64_t sleep_ns = (rqtp.tv_sec * 1'000'000'000) + rqtp.tv_nsec;
|
||||
if (sleep_ns == 0)
|
||||
return 0;
|
||||
const uint64_t waketime_ns = [&rqtp, current_ns]() -> uint64_t {
|
||||
if (BAN::Math::will_multiplication_overflow<uint64_t>(rqtp.tv_sec, 1'000'000'000))
|
||||
return BAN::numeric_limits<uint64_t>::max();
|
||||
if (BAN::Math::will_addition_overflow<uint64_t>(rqtp.tv_sec * 1'000'000'000, rqtp.tv_nsec))
|
||||
return BAN::numeric_limits<uint64_t>::max();
|
||||
if (BAN::Math::will_addition_overflow<uint64_t>(rqtp.tv_sec * 1'000'000'000 + rqtp.tv_nsec, current_ns))
|
||||
return BAN::numeric_limits<uint64_t>::max();
|
||||
return rqtp.tv_sec * 1'000'000'000 + rqtp.tv_nsec + current_ns;
|
||||
}();
|
||||
|
||||
const uint64_t wake_time_ns = SystemTimer::get().ns_since_boot() + sleep_ns;
|
||||
SystemTimer::get().sleep_ns(sleep_ns);
|
||||
|
||||
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
||||
if (current_ns < wake_time_ns)
|
||||
// NOTE: we shouldn't get woken up unless the thread is interrupted but there is no harm in looping
|
||||
while (current_ns < waketime_ns && !Thread::current().is_interrupted_by_signal())
|
||||
{
|
||||
SystemTimer::get().sleep_until_ns(waketime_ns);
|
||||
current_ns = SystemTimer::get().ns_since_boot();
|
||||
}
|
||||
|
||||
if (current_ns < waketime_ns)
|
||||
{
|
||||
const uint64_t remaining_ns = wake_time_ns - current_ns;
|
||||
const timespec remaining_ts = {
|
||||
.tv_sec = static_cast<time_t>(remaining_ns / 1'000'000'000),
|
||||
.tv_nsec = static_cast<long>(remaining_ns % 1'000'000'000),
|
||||
};
|
||||
if (user_rmtp != nullptr)
|
||||
{
|
||||
const uint64_t remaining_ns = waketime_ns - current_ns;
|
||||
const timespec remaining_ts = {
|
||||
.tv_sec = static_cast<time_t>(remaining_ns / 1'000'000'000),
|
||||
.tv_nsec = static_cast<long>(remaining_ns % 1'000'000'000),
|
||||
};
|
||||
TRY(write_to_user(user_rmtp, &remaining_ts, sizeof(timespec)));
|
||||
}
|
||||
return BAN::Error::from_errno(EINTR);
|
||||
}
|
||||
|
||||
@@ -1851,7 +2043,7 @@ namespace Kernel
|
||||
return TRY(m_open_file_descriptors.sendmsg(socket, message, flags));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_ioctl(int fildes, int request, void* arg)
|
||||
BAN::ErrorOr<long> Process::sys_ioctl(int fildes, unsigned long request, void* arg)
|
||||
{
|
||||
auto inode = TRY(m_open_file_descriptors.inode_of(fildes));
|
||||
return TRY(inode->ioctl(request, arg));
|
||||
@@ -2663,9 +2855,9 @@ namespace Kernel
|
||||
if (prot & PROT_READ)
|
||||
flags |= PageTable::Flags::Present;
|
||||
if (prot & PROT_WRITE)
|
||||
flags |= PageTable::Flags::ReadWrite | PageTable::Flags::Present;
|
||||
flags |= PageTable::Flags::Present | PageTable::Flags::ReadWrite;
|
||||
if (prot & PROT_EXEC)
|
||||
flags |= PageTable::Flags::Execute | PageTable::Flags::Execute;
|
||||
flags |= PageTable::Flags::Present | PageTable::Flags::Execute;
|
||||
|
||||
if (flags == 0)
|
||||
flags = PageTable::Flags::Reserved;
|
||||
@@ -2964,6 +3156,9 @@ namespace Kernel
|
||||
|
||||
void Process::wait_while_stopped()
|
||||
{
|
||||
if (!m_stopped) [[likely]]
|
||||
return;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (Thread::current().will_exit_because_of_signal())
|
||||
@@ -3354,41 +3549,63 @@ namespace Kernel
|
||||
return Thread::current().get_gsbase();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pthread_create(const pthread_attr_t* user_attr, void (*entry)(void*), void* arg)
|
||||
BAN::ErrorOr<long> Process::sys_thread_create(void (*entry)(void*), void* arg, void* stack_base, size_t stack_size)
|
||||
{
|
||||
if (user_attr != nullptr)
|
||||
dwarnln("TODO: ignoring thread attr");
|
||||
const vaddr_t stack_vaddr = reinterpret_cast<vaddr_t>(stack_base);
|
||||
if (stack_vaddr % PAGE_SIZE || stack_size % PAGE_SIZE)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
LockGuard _(m_process_lock);
|
||||
auto* memory_region = TRY(validate_and_pin_pointer_access(stack_base, stack_size, true));
|
||||
BAN::ScopeGuard _0([memory_region] { if (memory_region) memory_region->unpin(); });
|
||||
|
||||
auto* new_thread = TRY(Thread::current().pthread_create(entry, arg));
|
||||
MUST(m_threads.push_back(new_thread));
|
||||
MUST(Processor::scheduler().add_thread(new_thread));
|
||||
const vaddr_t initial_stack_pointer = stack_vaddr + stack_size - sizeof(void*);
|
||||
*reinterpret_cast<void**>(initial_stack_pointer) = arg;
|
||||
|
||||
return new_thread->tid();
|
||||
}
|
||||
auto* thread = TRY(Thread::create_userspace(
|
||||
this,
|
||||
page_table(),
|
||||
stack_vaddr,
|
||||
stack_size,
|
||||
reinterpret_cast<vaddr_t>(entry),
|
||||
initial_stack_pointer
|
||||
));
|
||||
thread->m_signal_block_mask = Thread::current().m_signal_block_mask;
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pthread_exit(void* value)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
LockGuard _1(m_process_lock);
|
||||
|
||||
if (m_threads.size() == 1)
|
||||
return sys_exit(0);
|
||||
|
||||
auto& thread = Thread::current();
|
||||
if (!thread.is_detached())
|
||||
TRY(m_threads.push_back(thread));
|
||||
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error())
|
||||
{
|
||||
TRY(m_exited_pthreads.emplace_back(thread.tid(), value));
|
||||
m_pthread_exit_blocker.unblock();
|
||||
m_threads.pop_back();
|
||||
delete thread;
|
||||
return ret.release_error();
|
||||
}
|
||||
|
||||
m_process_lock.unlock();
|
||||
thread.on_exit();
|
||||
return thread->tid();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_thread_exit(void* value)
|
||||
{
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
|
||||
if (m_threads.size() == 1)
|
||||
return sys_exit(0);
|
||||
|
||||
auto& thread = Thread::current();
|
||||
if (!thread.is_detached())
|
||||
{
|
||||
TRY(m_exited_threads.emplace_back(thread.tid(), value));
|
||||
m_thread_exit_blocker.unblock();
|
||||
}
|
||||
}
|
||||
|
||||
Thread::current().on_exit();
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pthread_join(pthread_t tid, void** user_value)
|
||||
BAN::ErrorOr<long> Process::sys_thread_join(pid_t tid, void** user_value)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
|
||||
@@ -3398,12 +3615,12 @@ namespace Kernel
|
||||
const auto check_thread =
|
||||
[&]() -> BAN::Optional<void*>
|
||||
{
|
||||
for (size_t i = 0; i < m_exited_pthreads.size(); i++)
|
||||
for (size_t i = 0; i < m_exited_threads.size(); i++)
|
||||
{
|
||||
if (m_exited_pthreads[i].thread != tid)
|
||||
if (m_exited_threads[i].tid != tid)
|
||||
continue;
|
||||
void* ret = m_exited_pthreads[i].value;
|
||||
m_exited_pthreads.remove(i);
|
||||
void* ret = m_exited_threads[i].value;
|
||||
m_exited_threads.remove(i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3436,16 +3653,16 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
TRY(Thread::current().block_or_eintr_indefinite(m_pthread_exit_blocker, &m_process_lock));
|
||||
TRY(Thread::current().block_or_eintr_indefinite(m_thread_exit_blocker, &m_process_lock));
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pthread_self()
|
||||
BAN::ErrorOr<long> Process::sys_thread_getid()
|
||||
{
|
||||
return Thread::current().tid();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pthread_kill(pthread_t tid, int signal)
|
||||
BAN::ErrorOr<long> Process::sys_thread_kill(pid_t tid, int signal)
|
||||
{
|
||||
if (signal != 0 && (signal < _SIGMIN || signal > _SIGMAX))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
@@ -3475,7 +3692,7 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ESRCH);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pthread_detach(pthread_t tid)
|
||||
BAN::ErrorOr<long> Process::sys_thread_detach(pid_t tid)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
|
||||
@@ -3486,7 +3703,7 @@ namespace Kernel
|
||||
if (thread->is_detached())
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
thread->detach();
|
||||
m_pthread_exit_blocker.unblock();
|
||||
m_thread_exit_blocker.unblock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <kernel/CPUID.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Memory/Heap.h>
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
@@ -20,6 +21,8 @@ namespace Kernel
|
||||
static constexpr uint32_t MSR_IA32_FMASK = 0xC0000084;
|
||||
#endif
|
||||
|
||||
static constexpr uint32_t MSR_IA32_TSC_AUX = 0xC0000103;
|
||||
|
||||
ProcessorID Processor::s_bsp_id { PROCESSOR_NONE };
|
||||
BAN::Atomic<uint8_t> Processor::s_processor_count { 0 };
|
||||
BAN::Atomic<bool> Processor::s_is_smp_enabled { false };
|
||||
@@ -219,6 +222,9 @@ namespace Kernel
|
||||
shared_page.gdt_cpu_offset = GDT::cpu_index_offset();
|
||||
shared_page.features = 0;
|
||||
|
||||
if (CPUID::has_rdtscp())
|
||||
shared_page.features |= API::SPF_RDTSCP;
|
||||
|
||||
ASSERT(Processor::count() + sizeof(Kernel::API::SharedPage) <= PAGE_SIZE);
|
||||
}
|
||||
|
||||
@@ -289,13 +295,11 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
void Processor::initialize_tsc(uint8_t shift, uint64_t mult, uint64_t realtime_seconds)
|
||||
void Processor::initialize_tsc(uint64_t realtime_seconds)
|
||||
{
|
||||
auto& shared_page = Processor::shared_page();
|
||||
|
||||
shared_page.gettime_shared.shift = shift;
|
||||
shared_page.gettime_shared.mult = mult;
|
||||
shared_page.gettime_shared.realtime_seconds = realtime_seconds;
|
||||
shared_page.gettime_shared.realtime_s = realtime_seconds;
|
||||
shared_page.gettime_shared.realtime_ns = 0;
|
||||
|
||||
update_tsc();
|
||||
|
||||
@@ -322,23 +326,63 @@ namespace Kernel
|
||||
|
||||
void Processor::update_tsc()
|
||||
{
|
||||
auto& sgettime = shared_page().cpus[current_index()].gettime_local;
|
||||
sgettime.seq = sgettime.seq + 1;
|
||||
sgettime.last_ns = SystemTimer::get().ns_since_boot_no_tsc();
|
||||
sgettime.last_tsc = __builtin_ia32_rdtsc();
|
||||
sgettime.seq = sgettime.seq + 1;
|
||||
auto& lgettime = shared_page().cpus[current_index()].gettime_local;
|
||||
|
||||
const auto seq = BAN::atomic_load(lgettime.seq, BAN::memory_order_relaxed);
|
||||
|
||||
BAN::atomic_store(lgettime.seq, seq + 1, BAN::memory_order_release);
|
||||
|
||||
if (lgettime.seq == 1)
|
||||
{
|
||||
const auto tsc_info = SystemTimer::get().tsc_info();
|
||||
lgettime.shift = tsc_info.shift;
|
||||
lgettime.mult = tsc_info.mult;
|
||||
lgettime.last_ns = SystemTimer::get().ns_since_boot_no_tsc();
|
||||
lgettime.last_tsc = __builtin_ia32_rdtsc();
|
||||
|
||||
if (CPUID::has_rdtscp())
|
||||
asm volatile("wrmsr" :: "d"(0x00000000), "a"(current_index()), "c"(MSR_IA32_TSC_AUX));
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto current_ns = SystemTimer::get().ns_since_boot_no_tsc();
|
||||
const auto current_tsc = __builtin_ia32_rdtsc();
|
||||
|
||||
auto delta_ns = current_tsc - lgettime.last_tsc;
|
||||
if (lgettime.shift >= 0)
|
||||
delta_ns <<= lgettime.shift;
|
||||
else
|
||||
delta_ns >>= -lgettime.shift;
|
||||
delta_ns = (delta_ns * lgettime.mult) >> 32;
|
||||
|
||||
lgettime.last_ns += delta_ns;
|
||||
lgettime.last_tsc = current_tsc;
|
||||
|
||||
// scale mult by [-0.25%, 0.25%] to fix for clock drift
|
||||
const auto error_ns = static_cast<int64_t>(current_ns) - static_cast<int64_t>(lgettime.last_ns);
|
||||
const auto correction_ppm = BAN::Math::clamp<int64_t>(error_ns * 1'000'000 / 1'000'000'000, -100, 100);
|
||||
const auto correction_delta = -lgettime.mult * correction_ppm / 1'000'000;
|
||||
lgettime.mult += correction_delta;
|
||||
}
|
||||
|
||||
BAN::atomic_store(lgettime.seq, seq + 2, BAN::memory_order_release);
|
||||
}
|
||||
|
||||
uint64_t Processor::ns_since_boot_tsc()
|
||||
{
|
||||
const auto& shared_page = Processor::shared_page();
|
||||
const auto& sgettime = shared_page.gettime_shared;
|
||||
const auto& lgettime = shared_page.cpus[current_index()].gettime_local;
|
||||
|
||||
auto state = get_interrupt_state();
|
||||
set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
const auto current_ns = lgettime.last_ns + (((__builtin_ia32_rdtsc() - lgettime.last_tsc) * sgettime.mult) >> sgettime.shift);
|
||||
uint64_t current_ns = __builtin_ia32_rdtsc() - lgettime.last_tsc;
|
||||
if (lgettime.shift >= 0)
|
||||
current_ns <<= lgettime.shift;
|
||||
else
|
||||
current_ns >>= -lgettime.shift;
|
||||
current_ns = (current_ns * lgettime.mult) >> 32;
|
||||
current_ns += lgettime.last_ns;
|
||||
|
||||
set_interrupt_state(state);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/Sort.h>
|
||||
#include <kernel/APIC.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/Process.h>
|
||||
@@ -45,12 +46,15 @@ namespace Kernel
|
||||
m_tail = node;
|
||||
}
|
||||
|
||||
void SchedulerQueue::add_thread_with_wake_time(Node* 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)
|
||||
return add_thread_to_back(node);
|
||||
{
|
||||
add_thread_to_back(node);
|
||||
return node == m_head;
|
||||
}
|
||||
|
||||
Node* next = m_head;
|
||||
Node* prev = nullptr;
|
||||
@@ -64,6 +68,8 @@ namespace Kernel
|
||||
node->prev = prev;
|
||||
(next ? next->prev : m_tail) = node;
|
||||
(prev ? prev->next : m_head) = node;
|
||||
|
||||
return node == m_head;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
@@ -122,15 +128,9 @@ namespace Kernel
|
||||
m_idle_thread = TRY(Thread::create_kernel([](void*) { asm volatile("1: hlt; jmp 1b"); }, nullptr));
|
||||
ASSERT(m_idle_thread);
|
||||
|
||||
size_t processor_index = 0;
|
||||
for (; processor_index < Processor::count(); processor_index++)
|
||||
if (Processor::id_from_index(processor_index) == Processor::current_id())
|
||||
break;
|
||||
ASSERT(processor_index < Processor::count());
|
||||
|
||||
// each CPU does load balance at different times. This calulates the offset to other CPUs
|
||||
m_last_load_balance_ns = s_load_balance_interval_ns * processor_index / Processor::count();
|
||||
m_idle_ns = -m_last_load_balance_ns;
|
||||
m_last_load_balance_ns = s_load_balance_interval_ns * Processor::current_index() / Processor::count();
|
||||
m_idle_ns = m_last_load_balance_ns;
|
||||
|
||||
s_schedulers_initialized++;
|
||||
while (s_schedulers_initialized < Processor::count())
|
||||
@@ -139,8 +139,6 @@ namespace Kernel
|
||||
if (Processor::count() > 1)
|
||||
Processor::set_smp_enabled();
|
||||
|
||||
m_next_reschedule_ns = SystemTimer::get().ns_since_boot();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -232,17 +230,14 @@ namespace Kernel
|
||||
m_thread_count--;
|
||||
break;
|
||||
case Thread::State::Executing:
|
||||
{
|
||||
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
||||
m_current->thread->yield_registers() = *yield_registers;
|
||||
m_current->time_used_ns += current_ns - 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);
|
||||
if (!m_current->blocked)
|
||||
m_run_queue.add_thread_to_back(m_current);
|
||||
else
|
||||
m_block_queue.add_thread_with_wake_time(m_current);
|
||||
else if (m_block_queue.add_thread_with_wake_time(m_current))
|
||||
update_wake_up_deadline();
|
||||
break;
|
||||
}
|
||||
case Thread::State::NotStarted:
|
||||
ASSERT(!m_current->blocked);
|
||||
m_current->time_used_ns = 0;
|
||||
@@ -321,26 +316,50 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
void Scheduler::update_wake_up_deadline()
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
auto& interrupt_controller = InterruptController::get();
|
||||
|
||||
// TODO: support timer deadlines on non-apic timers and abstract it :)
|
||||
if (!interrupt_controller.is_using_apic())
|
||||
return;
|
||||
|
||||
wake_up_sleeping_threads();
|
||||
|
||||
uint64_t deadline_ns = m_next_reschedule_ns;
|
||||
if (!m_block_queue.empty())
|
||||
deadline_ns = BAN::Math::min(deadline_ns, m_block_queue.front()->wake_time_ns);
|
||||
if (Processor::is_smp_enabled())
|
||||
deadline_ns = BAN::Math::min(deadline_ns, m_last_load_balance_ns + s_load_balance_interval_ns);
|
||||
|
||||
static_cast<APIC&>(interrupt_controller).set_timer_dealine(deadline_ns);
|
||||
}
|
||||
|
||||
void Scheduler::reschedule_if_idle()
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
if (m_current != nullptr)
|
||||
return;
|
||||
|
||||
if (m_run_queue.empty())
|
||||
wake_up_sleeping_threads();
|
||||
|
||||
if (!m_run_queue.empty())
|
||||
if (m_current == nullptr && !m_run_queue.empty())
|
||||
Processor::yield();
|
||||
}
|
||||
|
||||
extern "C" void scheduler_on_yield(YieldRegisters* yield_registers)
|
||||
extern "C" void scheduler_on_yield_trampoline(YieldRegisters* yield_registers)
|
||||
{
|
||||
Processor::scheduler().reschedule(yield_registers);
|
||||
Processor::scheduler().on_yield(yield_registers);
|
||||
}
|
||||
|
||||
void Scheduler::timer_interrupt()
|
||||
void Scheduler::on_yield(YieldRegisters* yield_registers)
|
||||
{
|
||||
reschedule(yield_registers);
|
||||
m_next_reschedule_ns = !is_idle()
|
||||
? SystemTimer::get().ns_since_boot() + s_reschedule_interval_ns
|
||||
: BAN::numeric_limits<uint64_t>::max();
|
||||
update_wake_up_deadline();
|
||||
}
|
||||
|
||||
void Scheduler::on_timer_interrupt()
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
@@ -349,11 +368,8 @@ namespace Kernel
|
||||
|
||||
wake_up_sleeping_threads();
|
||||
|
||||
if (SystemTimer::get().ns_since_boot() >= m_next_reschedule_ns)
|
||||
{
|
||||
m_next_reschedule_ns += s_reschedule_interval_ns;
|
||||
if (is_idle() || SystemTimer::get().ns_since_boot() >= m_next_reschedule_ns)
|
||||
Processor::yield();
|
||||
}
|
||||
}
|
||||
|
||||
void Scheduler::unblock_thread(SchedulerQueue::Node* node)
|
||||
@@ -394,8 +410,8 @@ namespace Kernel
|
||||
|
||||
if (!node->blocked)
|
||||
m_run_queue.add_thread_to_back(node);
|
||||
else
|
||||
m_block_queue.add_thread_with_wake_time(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();
|
||||
|
||||
@@ -7,6 +7,16 @@
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<AHCIController>> AHCIController::create(PCI::Device& pci_device)
|
||||
{
|
||||
auto* controller_ptr = new AHCIController(pci_device);
|
||||
if (controller_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto controller = BAN::RefPtr<AHCIController>::adopt(controller_ptr);
|
||||
TRY(controller->initialize());
|
||||
return controller;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> AHCIController::initialize()
|
||||
{
|
||||
m_abar = TRY(m_pci_device.allocate_bar_region(5));
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Kernel
|
||||
|
||||
static void select_delay()
|
||||
{
|
||||
SystemTimer::get().sleep_ns(400);
|
||||
SystemTimer::get().sleep_for_ns(400);
|
||||
}
|
||||
|
||||
void ATABus::select_device(bool is_secondary)
|
||||
@@ -87,7 +87,7 @@ namespace Kernel
|
||||
io_write(ATA_PORT_LBA1, 0);
|
||||
io_write(ATA_PORT_LBA2, 0);
|
||||
io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY);
|
||||
SystemTimer::get().sleep_ms(1);
|
||||
SystemTimer::get().sleep_for_ms(1);
|
||||
|
||||
// No device on port
|
||||
if (io_read(ATA_PORT_STATUS) == 0)
|
||||
@@ -112,7 +112,7 @@ namespace Kernel
|
||||
}
|
||||
|
||||
io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET);
|
||||
SystemTimer::get().sleep_ms(1);
|
||||
SystemTimer::get().sleep_for_ms(1);
|
||||
}
|
||||
|
||||
TRY(wait(true));
|
||||
|
||||
@@ -9,29 +9,12 @@
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<StorageController>> ATAController::create(PCI::Device& pci_device)
|
||||
BAN::ErrorOr<BAN::RefPtr<ATAController>> ATAController::create(PCI::Device& pci_device)
|
||||
{
|
||||
StorageController* controller_ptr = nullptr;
|
||||
|
||||
switch (pci_device.subclass())
|
||||
{
|
||||
case 0x01:
|
||||
controller_ptr = new ATAController(pci_device);
|
||||
break;
|
||||
case 0x05:
|
||||
dwarnln("unsupported DMA ATA Controller");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
case 0x06:
|
||||
controller_ptr = new AHCIController(pci_device);
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
auto* controller_ptr = new ATAController(pci_device);
|
||||
if (controller_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
|
||||
auto controller = BAN::RefPtr<StorageController>::adopt(controller_ptr);
|
||||
auto controller = BAN::RefPtr<ATAController>::adopt(controller_ptr);
|
||||
TRY(controller->initialize());
|
||||
return controller;
|
||||
}
|
||||
|
||||
@@ -16,12 +16,12 @@ namespace Kernel
|
||||
return minor++;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<StorageController>> NVMeController::create(PCI::Device& pci_device)
|
||||
BAN::ErrorOr<BAN::RefPtr<NVMeController>> NVMeController::create(PCI::Device& pci_device)
|
||||
{
|
||||
auto* controller_ptr = new NVMeController(pci_device);
|
||||
if (controller_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto controller = BAN::RefPtr<StorageController>::adopt(controller_ptr);
|
||||
auto controller = BAN::RefPtr<NVMeController>::adopt(controller_ptr);
|
||||
TRY(controller->initialize());
|
||||
return controller;
|
||||
}
|
||||
@@ -115,8 +115,6 @@ namespace Kernel
|
||||
|
||||
DevFileSystem::get().add_device(this);
|
||||
|
||||
StorageController::ref();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace Kernel
|
||||
slave->m_write_blocker.unblock();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> PseudoTerminalMaster::ioctl_impl(int request, void* argument)
|
||||
BAN::ErrorOr<long> PseudoTerminalMaster::ioctl_impl(unsigned long request, void* argument)
|
||||
{
|
||||
switch (request)
|
||||
{
|
||||
@@ -174,7 +174,7 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
}
|
||||
|
||||
return CharacterDevice::ioctl(request, argument);
|
||||
return CharacterDevice::ioctl_impl(request, argument);
|
||||
}
|
||||
|
||||
PseudoTerminalSlave::PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t mode, uid_t uid, gid_t gid)
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace Kernel
|
||||
(void)Process::kill(-m_foreground_pgrp, SIGWINCH);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> TTY::ioctl_impl(int request, void* argument)
|
||||
BAN::ErrorOr<long> TTY::ioctl_impl(unsigned long request, void* argument)
|
||||
{
|
||||
switch (request)
|
||||
{
|
||||
@@ -204,7 +204,7 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
return CharacterDevice::ioctl(request, argument);
|
||||
return CharacterDevice::ioctl_impl(request, argument);
|
||||
}
|
||||
|
||||
void TTY::on_key_event(LibInput::RawKeyEvent event)
|
||||
@@ -449,9 +449,14 @@ namespace Kernel
|
||||
void TTY::putchar_current(uint8_t ch)
|
||||
{
|
||||
ASSERT(s_tty);
|
||||
LockGuard _(s_tty->m_write_lock);
|
||||
|
||||
while (!s_tty->m_write_lock.try_lock())
|
||||
Processor::pause();
|
||||
|
||||
s_tty->putchar(ch);
|
||||
s_tty->after_write();
|
||||
|
||||
s_tty->m_write_lock.unlock();
|
||||
}
|
||||
|
||||
bool TTY::is_initialized()
|
||||
|
||||
@@ -137,25 +137,25 @@ namespace Kernel
|
||||
case 7: m_colors_inverted = true; break;
|
||||
case 27: m_colors_inverted = false; break;
|
||||
|
||||
case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37:
|
||||
case 30 ... 37:
|
||||
m_foreground = m_palette[value - 30];
|
||||
break;
|
||||
case 39:
|
||||
m_foreground = m_palette[15];
|
||||
break;
|
||||
|
||||
case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47:
|
||||
case 40 ... 47:
|
||||
m_background = m_palette[value - 40];
|
||||
break;
|
||||
case 49:
|
||||
m_background = m_palette[0];
|
||||
break;
|
||||
|
||||
case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97:
|
||||
case 90 ... 97:
|
||||
m_foreground = m_palette[value - 90 + 8];
|
||||
break;
|
||||
|
||||
case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107:
|
||||
case 100 ... 107:
|
||||
m_background = m_palette[value - 100 + 8];
|
||||
break;
|
||||
|
||||
@@ -204,9 +204,7 @@ namespace Kernel
|
||||
ASSERT(m_write_lock.is_locked_by_current_thread());
|
||||
switch (ch)
|
||||
{
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
{
|
||||
case '0' ... '9':
|
||||
if (m_ansi_state.index >= m_ansi_state.max_nums)
|
||||
dwarnln("Only {} arguments supported with ANSI codes", m_ansi_state.max_nums);
|
||||
else
|
||||
@@ -215,7 +213,6 @@ namespace Kernel
|
||||
val = (val == -1) ? (ch - '0') : (val * 10 + ch - '0');
|
||||
}
|
||||
return;
|
||||
}
|
||||
case ';':
|
||||
m_ansi_state.index = BAN::Math::min<size_t>(m_ansi_state.index + 1, m_ansi_state.max_nums);
|
||||
return;
|
||||
|
||||
@@ -15,15 +15,9 @@
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
static_assert(SYS_SIGPROCMASK == 79, "this is hard coded in arch/*/Signal.S");
|
||||
static_assert(SYS_SIGPROCMASK == 78, "this is hard coded in arch/*/Signal.S");
|
||||
static_assert(SIG_SETMASK == 3, "this is hard coded in arch/*/Signal.S");
|
||||
|
||||
#if ARCH(x86_64)
|
||||
static constexpr vaddr_t s_user_stack_addr_start = 0x0000700000000000;
|
||||
#elif ARCH(i686)
|
||||
static constexpr vaddr_t s_user_stack_addr_start = 0xB0000000;
|
||||
#endif
|
||||
|
||||
extern "C" [[noreturn]] void start_kernel_thread();
|
||||
extern "C" [[noreturn]] void start_userspace_thread();
|
||||
|
||||
@@ -198,7 +192,7 @@ namespace Kernel
|
||||
return thread;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Thread*> Thread::create_userspace(Process* process, PageTable& page_table)
|
||||
BAN::ErrorOr<Thread*> Thread::create_userspace(Process* process, PageTable& page_table, vaddr_t userspace_stack_vaddr, size_t userspace_stack_size, vaddr_t entry_point, vaddr_t stack_pointer)
|
||||
{
|
||||
ASSERT(process);
|
||||
|
||||
@@ -212,22 +206,32 @@ namespace Kernel
|
||||
|
||||
thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
|
||||
page_table,
|
||||
{ s_user_stack_addr_start, USERSPACE_END },
|
||||
{ userspace_stack_base, USERSPACE_END },
|
||||
kernel_stack_size,
|
||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
true
|
||||
));
|
||||
|
||||
auto userspace_stack = TRY(MemoryBackedRegion::create(
|
||||
page_table,
|
||||
userspace_stack_size,
|
||||
{ s_user_stack_addr_start, USERSPACE_END },
|
||||
MemoryRegion::Type::PRIVATE,
|
||||
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
O_RDWR
|
||||
));
|
||||
thread->m_userspace_stack = userspace_stack.ptr();
|
||||
TRY(process->add_mapped_region(BAN::move(userspace_stack)));
|
||||
thread->m_userspace_stack_vaddr = userspace_stack_vaddr;
|
||||
thread->m_userspace_stack_size = userspace_stack_size;
|
||||
|
||||
// Initialize stack for returning
|
||||
PageTable::with_fast_page(thread->kernel_stack().paddr_of(thread->kernel_stack_top() - PAGE_SIZE), [=] {
|
||||
uintptr_t cur_sp = PageTable::fast_page() + PAGE_SIZE;
|
||||
write_to_stack(cur_sp, 0x20 | 3);
|
||||
write_to_stack(cur_sp, stack_pointer);
|
||||
write_to_stack(cur_sp, 0x202);
|
||||
#if ARCH(x86_64)
|
||||
write_to_stack(cur_sp, 0x28 | 3);
|
||||
#elif ARCH(i686)
|
||||
write_to_stack(cur_sp, 0x18 | 3);
|
||||
#endif
|
||||
write_to_stack(cur_sp, entry_point);
|
||||
});
|
||||
|
||||
thread->m_yield_registers = {};
|
||||
thread->m_yield_registers.ip = reinterpret_cast<vaddr_t>(start_userspace_thread);
|
||||
thread->m_yield_registers.sp = thread->kernel_stack_top() - 5 * sizeof(uintptr_t);
|
||||
|
||||
thread_deleter.disable();
|
||||
|
||||
@@ -311,26 +315,6 @@ namespace Kernel
|
||||
Processor::gdt().set_cpu_index(Processor::current_index());
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Thread*> Thread::pthread_create(entry_t entry, void* arg)
|
||||
{
|
||||
auto* thread = TRY(create_userspace(m_process, m_process->page_table()));
|
||||
|
||||
if (Processor::get_current_sse_thread() == this)
|
||||
save_sse();
|
||||
memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage));
|
||||
|
||||
TRY(thread->userspace_stack().copy_data_to_region(
|
||||
thread->m_userspace_stack->size() - sizeof(void*),
|
||||
reinterpret_cast<const uint8_t*>(&arg),
|
||||
sizeof(void*)
|
||||
));
|
||||
|
||||
const vaddr_t entry_addr = reinterpret_cast<vaddr_t>(entry);
|
||||
thread->setup_exec(entry_addr, thread->userspace_stack().vaddr() + thread->userspace_stack().size() - sizeof(void*));
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Thread*> Thread::clone(Process* new_process, uintptr_t sp, uintptr_t ip)
|
||||
{
|
||||
ASSERT(m_is_userspace);
|
||||
@@ -345,7 +329,7 @@ namespace Kernel
|
||||
|
||||
thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
|
||||
new_process->page_table(),
|
||||
{ s_user_stack_addr_start, USERSPACE_END },
|
||||
{ userspace_stack_base, USERSPACE_END },
|
||||
kernel_stack_size,
|
||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
true
|
||||
@@ -362,9 +346,8 @@ namespace Kernel
|
||||
);
|
||||
});
|
||||
|
||||
const auto stack_index = new_process->find_mapped_region(m_userspace_stack->vaddr());
|
||||
thread->m_userspace_stack = static_cast<MemoryBackedRegion*>(new_process->m_mapped_regions[stack_index].ptr());
|
||||
ASSERT(thread->m_userspace_stack->vaddr() == m_userspace_stack->vaddr());
|
||||
thread->m_userspace_stack_vaddr = m_userspace_stack_vaddr;
|
||||
thread->m_userspace_stack_size = m_userspace_stack_size;
|
||||
|
||||
thread->m_fsbase = m_fsbase;
|
||||
thread->m_gsbase = m_gsbase;
|
||||
@@ -385,151 +368,23 @@ namespace Kernel
|
||||
return thread;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Thread::initialize_userspace(vaddr_t entry, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv)
|
||||
{
|
||||
// System V ABI: Initial process stack
|
||||
|
||||
ASSERT(m_is_userspace);
|
||||
ASSERT(m_userspace_stack);
|
||||
|
||||
size_t needed_size = 0;
|
||||
|
||||
// argc
|
||||
needed_size += sizeof(uintptr_t);
|
||||
|
||||
// argv
|
||||
needed_size += (argv.size() + 1) * sizeof(uintptr_t);
|
||||
for (auto arg : argv)
|
||||
needed_size += arg.size() + 1;
|
||||
|
||||
// envp
|
||||
needed_size += (envp.size() + 1) * sizeof(uintptr_t);
|
||||
for (auto env : envp)
|
||||
needed_size += env.size() + 1;
|
||||
|
||||
// auxv
|
||||
needed_size += auxv.size() * sizeof(LibELF::AuxiliaryVector);
|
||||
|
||||
if (auto rem = needed_size % alignof(char*))
|
||||
needed_size += alignof(char*) - rem;
|
||||
|
||||
if (needed_size > m_userspace_stack->size())
|
||||
return BAN::Error::from_errno(ENOBUFS);
|
||||
|
||||
vaddr_t vaddr = userspace_stack().vaddr() + userspace_stack().size() - needed_size;
|
||||
|
||||
const size_t page_count = BAN::Math::div_round_up<size_t>(needed_size, PAGE_SIZE);
|
||||
for (size_t i = 0; i < page_count; i++)
|
||||
TRY(m_userspace_stack->allocate_page_containing(vaddr + i * PAGE_SIZE, true));
|
||||
|
||||
const auto stack_copy_buf =
|
||||
[this](BAN::ConstByteSpan buffer, vaddr_t vaddr) -> void
|
||||
{
|
||||
ASSERT(vaddr >= m_userspace_stack->vaddr());
|
||||
ASSERT(vaddr + buffer.size() <= m_userspace_stack->vaddr() + m_userspace_stack->size());
|
||||
MUST(m_userspace_stack->copy_data_to_region(vaddr - m_userspace_stack->vaddr(), buffer.data(), buffer.size()));
|
||||
};
|
||||
|
||||
const auto stack_push_buf =
|
||||
[&stack_copy_buf, &vaddr](BAN::ConstByteSpan buffer) -> void
|
||||
{
|
||||
stack_copy_buf(buffer, vaddr);
|
||||
vaddr += buffer.size();
|
||||
};
|
||||
|
||||
const auto stack_push_uint =
|
||||
[&stack_push_buf](uintptr_t value) -> void
|
||||
{
|
||||
stack_push_buf(BAN::ConstByteSpan::from(value));
|
||||
};
|
||||
|
||||
const auto stack_push_str =
|
||||
[&stack_push_buf](BAN::StringView string) -> void
|
||||
{
|
||||
const uint8_t* string_u8 = reinterpret_cast<const uint8_t*>(string.data());
|
||||
stack_push_buf(BAN::ConstByteSpan(string_u8, string.size() + 1));
|
||||
};
|
||||
|
||||
// argc
|
||||
stack_push_uint(argv.size());
|
||||
|
||||
// argv
|
||||
const vaddr_t argv_vaddr = vaddr;
|
||||
vaddr += argv.size() * sizeof(uintptr_t);
|
||||
stack_push_uint(0);
|
||||
|
||||
// envp
|
||||
const vaddr_t envp_vaddr = vaddr;
|
||||
vaddr += envp.size() * sizeof(uintptr_t);
|
||||
stack_push_uint(0);
|
||||
|
||||
// auxv
|
||||
for (auto aux : auxv)
|
||||
stack_push_buf(BAN::ConstByteSpan::from(aux));
|
||||
|
||||
// information
|
||||
for (size_t i = 0; i < argv.size(); i++)
|
||||
{
|
||||
stack_copy_buf(BAN::ConstByteSpan::from(vaddr), argv_vaddr + i * sizeof(uintptr_t));
|
||||
stack_push_str(argv[i]);
|
||||
}
|
||||
for (size_t i = 0; i < envp.size(); i++)
|
||||
{
|
||||
stack_copy_buf(BAN::ConstByteSpan::from(vaddr), envp_vaddr + i * sizeof(uintptr_t));
|
||||
stack_push_str(envp[i]);
|
||||
}
|
||||
|
||||
setup_exec(entry, m_userspace_stack->vaddr() + m_userspace_stack->size() - needed_size);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void Thread::setup_exec(vaddr_t ip, vaddr_t sp)
|
||||
{
|
||||
ASSERT(is_userspace());
|
||||
m_state = State::NotStarted;
|
||||
|
||||
// Signal mask is inherited
|
||||
|
||||
// Initialize stack for returning
|
||||
PageTable::with_fast_page(kernel_stack().paddr_of(kernel_stack_top() - PAGE_SIZE), [=] {
|
||||
uintptr_t cur_sp = PageTable::fast_page() + PAGE_SIZE;
|
||||
write_to_stack(cur_sp, 0x20 | 3);
|
||||
write_to_stack(cur_sp, sp);
|
||||
write_to_stack(cur_sp, 0x202);
|
||||
#if ARCH(x86_64)
|
||||
write_to_stack(cur_sp, 0x28 | 3);
|
||||
#elif ARCH(i686)
|
||||
write_to_stack(cur_sp, 0x18 | 3);
|
||||
#endif
|
||||
write_to_stack(cur_sp, ip);
|
||||
});
|
||||
|
||||
m_yield_registers = {};
|
||||
m_yield_registers.ip = reinterpret_cast<vaddr_t>(start_userspace_thread);
|
||||
m_yield_registers.sp = kernel_stack_top() - 5 * sizeof(uintptr_t);
|
||||
}
|
||||
|
||||
void Thread::setup_process_cleanup()
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
static entry_t entry = [](void* process_ptr) {
|
||||
auto* thread = &Thread::current();
|
||||
auto* process = static_cast<Process*>(process_ptr);
|
||||
ASSERT(thread->m_process == process);
|
||||
|
||||
process->cleanup_function(thread);
|
||||
|
||||
thread->m_delete_process = true;
|
||||
|
||||
// will call on thread exit after return
|
||||
};
|
||||
|
||||
m_state = State::NotStarted;
|
||||
static entry_t entry(
|
||||
[](void* process_ptr)
|
||||
{
|
||||
auto* thread = &Thread::current();
|
||||
auto* process = static_cast<Process*>(process_ptr);
|
||||
|
||||
ASSERT(thread->m_process == process);
|
||||
|
||||
process->cleanup_function(thread);
|
||||
|
||||
thread->m_delete_process = true;
|
||||
|
||||
// will call on thread exit after return
|
||||
}
|
||||
);
|
||||
|
||||
m_signal_pending_mask = 0;
|
||||
m_signal_block_mask = ~0ull;
|
||||
@@ -609,16 +464,15 @@ namespace Kernel
|
||||
SpinLockGuard _2(m_process->m_signal_lock);
|
||||
|
||||
const uint64_t process_signal_pending_mask = m_process->m_signal_pending_mask;
|
||||
const uint64_t full_pending_mask = m_signal_pending_mask | process_signal_pending_mask;
|
||||
for (signal = _SIGMIN; signal <= _SIGMAX; signal++)
|
||||
{
|
||||
const uint64_t mask = 1ull << signal;
|
||||
if ((full_pending_mask & mask) && !(m_signal_block_mask & mask))
|
||||
break;
|
||||
}
|
||||
if (signal > _SIGMAX)
|
||||
const uint64_t full_pending_mask = (m_signal_pending_mask | process_signal_pending_mask) & ~m_signal_block_mask;
|
||||
if (full_pending_mask == 0) [[likely]]
|
||||
return false;
|
||||
|
||||
for (signal = _SIGMIN; signal <= _SIGMAX; signal++)
|
||||
if (full_pending_mask & (1ull << signal))
|
||||
break;
|
||||
ASSERT(signal <= _SIGMAX);
|
||||
|
||||
if (process_signal_pending_mask & (1ull << signal))
|
||||
signal_info = m_process->m_signal_infos[signal];
|
||||
else
|
||||
@@ -864,11 +718,21 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Thread::sleep_or_eintr_ns(uint64_t ns)
|
||||
BAN::ErrorOr<void> Thread::sleep_or_eintr_for_ns(uint64_t timeout_ns)
|
||||
{
|
||||
if (is_interrupted_by_signal(true))
|
||||
return BAN::Error::from_errno(EINTR);
|
||||
SystemTimer::get().sleep_ns(ns);
|
||||
SystemTimer::get().sleep_for_ns(timeout_ns);
|
||||
if (is_interrupted_by_signal(true))
|
||||
return BAN::Error::from_errno(EINTR);
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Thread::sleep_or_eintr_until_ns(uint64_t waketime_ns)
|
||||
{
|
||||
if (is_interrupted_by_signal(true))
|
||||
return BAN::Error::from_errno(EINTR);
|
||||
SystemTimer::get().sleep_until_ns(waketime_ns);
|
||||
if (is_interrupted_by_signal(true))
|
||||
return BAN::Error::from_errno(EINTR);
|
||||
return {};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <BAN/ScopeGuard.h>
|
||||
#include <kernel/ACPI/ACPI.h>
|
||||
#include <kernel/APIC.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
@@ -112,13 +113,13 @@ namespace Kernel
|
||||
static_assert(offsetof(HPETRegisters, timers[0]) == 0x100);
|
||||
static_assert(offsetof(HPETRegisters, timers[1]) == 0x120);
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<HPET>> HPET::create(bool force_pic)
|
||||
BAN::ErrorOr<BAN::UniqPtr<HPET>> HPET::create()
|
||||
{
|
||||
HPET* hpet_ptr = new HPET();
|
||||
if (hpet_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto hpet = BAN::UniqPtr<HPET>::adopt(hpet_ptr);
|
||||
TRY(hpet->initialize(force_pic));
|
||||
TRY(hpet->initialize());
|
||||
return hpet;
|
||||
}
|
||||
|
||||
@@ -129,7 +130,7 @@ namespace Kernel
|
||||
m_mmio_base = 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> HPET::initialize(bool force_pic)
|
||||
BAN::ErrorOr<void> HPET::initialize()
|
||||
{
|
||||
auto* header = static_cast<const ACPI::HPET*>(ACPI::ACPI::get().get_header("HPET"_sv, 0));
|
||||
if (header == nullptr)
|
||||
@@ -138,7 +139,7 @@ namespace Kernel
|
||||
if (header->hardware_rev_id == 0)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
if (force_pic && !header->legacy_replacement_irq_routing_cable)
|
||||
if (!InterruptController::get().is_using_apic() && !header->legacy_replacement_irq_routing_cable)
|
||||
{
|
||||
dwarnln("HPET doesn't support legacy mapping");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
@@ -151,18 +152,19 @@ namespace Kernel
|
||||
|
||||
auto& regs = registers();
|
||||
|
||||
#if ARCH(x86_64)
|
||||
m_is_64bit = regs.capabilities & COUNT_SIZE_CAP;
|
||||
#else
|
||||
// spec: It is strongly recommended that 32-bit software only operate the timer in 32-bit mode.
|
||||
m_is_64bit = false;
|
||||
#endif
|
||||
|
||||
// Disable and reset main counter
|
||||
regs.configuration.low = regs.configuration.low & ~ENABLE_CNF;
|
||||
regs.main_counter.high = 0;
|
||||
regs.main_counter.low = 0;
|
||||
|
||||
// Enable legacy routing if available
|
||||
if (regs.capabilities & LEG_RT_CAP)
|
||||
regs.configuration.low = regs.configuration.low | LEG_RT_CNF;
|
||||
|
||||
uint32_t period_fs = regs.counter_clk_period;
|
||||
const uint32_t period_fs = regs.counter_clk_period;
|
||||
if (period_fs == 0 || period_fs > HPET_PERIOD_MAX)
|
||||
{
|
||||
dwarnln("HPET: Invalid counter period");
|
||||
@@ -172,7 +174,7 @@ namespace Kernel
|
||||
m_ticks_per_s = FS_PER_S / period_fs;
|
||||
dprintln("HPET frequency {} Hz", m_ticks_per_s);
|
||||
|
||||
uint8_t last_timer = (regs.capabilities & NUM_TIM_CAP_MASK) >> NUM_TIM_CAP_SHIFT;
|
||||
const uint8_t last_timer = (regs.capabilities & NUM_TIM_CAP_MASK) >> NUM_TIM_CAP_SHIFT;
|
||||
dprintln("HPET has {} timers", last_timer + 1);
|
||||
|
||||
// Disable all timers
|
||||
@@ -190,21 +192,54 @@ namespace Kernel
|
||||
}
|
||||
|
||||
// enable interrupts
|
||||
timer0.configuration = timer0.configuration | Tn_INT_ENB_CNF;
|
||||
// clear interrupt mask (set irq to 0)
|
||||
timer0.configuration = timer0.configuration & ~Tn_INT_ROUTE_CNF_MASK;
|
||||
timer0.configuration = timer0.configuration | Tn_INT_ENB_CNF;
|
||||
// edge triggered interrupts
|
||||
timer0.configuration = timer0.configuration & ~Tn_INT_TYPE_CNF;
|
||||
// periodic timer
|
||||
timer0.configuration = timer0.configuration | Tn_TYPE_CNF;
|
||||
timer0.configuration = timer0.configuration | Tn_TYPE_CNF;
|
||||
// disable 32 bit mode
|
||||
timer0.configuration = timer0.configuration & ~Tn_32MODE_CNF;
|
||||
// disable FSB interrupts
|
||||
if (timer0.configuration & Tn_FSB_INT_DEL_CAP)
|
||||
timer0.configuration = timer0.configuration & ~Tn_FSB_EN_CNF;
|
||||
|
||||
uint16_t irq;
|
||||
if (header->legacy_replacement_irq_routing_cable)
|
||||
{
|
||||
TRY(InterruptController::get().reserve_irq(0));
|
||||
irq = 0;
|
||||
|
||||
regs.configuration.low = regs.configuration.low | LEG_RT_CNF;
|
||||
timer0.configuration = timer0.configuration & ~Tn_INT_ROUTE_CNF_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(InterruptController::get().is_using_apic());
|
||||
auto& apic = static_cast<APIC&>(InterruptController::get());
|
||||
|
||||
uint8_t gsi = 0;
|
||||
for (; gsi < 32; gsi++)
|
||||
{
|
||||
if (!(timer0.int_route_cap & (1u << gsi)))
|
||||
continue;
|
||||
auto ret = apic.reserve_gsi(gsi);
|
||||
if (ret.is_error())
|
||||
continue;
|
||||
irq = ret.value();
|
||||
break;
|
||||
}
|
||||
if (gsi == 32)
|
||||
{
|
||||
dwarnln("Could not route any interrupt for HPET");
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
|
||||
regs.configuration.low = regs.configuration.low & ~LEG_RT_CNF;
|
||||
timer0.configuration = (timer0.configuration & ~Tn_INT_ROUTE_CNF_MASK) | (gsi << Tn_INT_ROUTE_CNF_SHIFT);
|
||||
}
|
||||
|
||||
// set timer period to 1000 Hz
|
||||
uint64_t ticks_per_ms = m_ticks_per_s / 1000;
|
||||
const uint64_t ticks_per_ms = m_ticks_per_s / 1000;
|
||||
timer0.configuration = timer0.configuration | Tn_VAL_SET_CNF;
|
||||
timer0.comparator.low = ticks_per_ms;
|
||||
if (timer0.configuration & Tn_SIZE_CAP)
|
||||
@@ -221,9 +256,8 @@ namespace Kernel
|
||||
// enable main counter
|
||||
regs.configuration.low = regs.configuration.low | ENABLE_CNF;
|
||||
|
||||
TRY(InterruptController::get().reserve_irq(0));
|
||||
set_irq(0);
|
||||
InterruptController::get().enable_irq(0);
|
||||
set_irq(irq);
|
||||
InterruptController::get().enable_irq(irq);
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -240,65 +274,62 @@ namespace Kernel
|
||||
|
||||
uint64_t HPET::read_main_counter() const
|
||||
{
|
||||
auto& regs = registers();
|
||||
const auto& regs = registers();
|
||||
|
||||
if (m_is_64bit)
|
||||
return regs.main_counter.full;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
uint32_t current_low = regs.main_counter.low;
|
||||
uint32_t wraps = m_32bit_wraps;
|
||||
if (current_low < (uint32_t)m_last_ticks)
|
||||
wraps++;
|
||||
return ((uint64_t)wraps << 32) | current_low;
|
||||
const uint32_t current_low = regs.main_counter.low;
|
||||
const uint32_t wraps = m_32bit_wraps + (current_low < static_cast<uint32_t>(m_last_ticks));
|
||||
return (static_cast<uint64_t>(wraps) << 32) | current_low;
|
||||
}
|
||||
|
||||
void HPET::handle_irq()
|
||||
{
|
||||
{
|
||||
auto& regs = registers();
|
||||
const auto& regs = registers();
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
uint64_t current_ticks;
|
||||
if (m_is_64bit)
|
||||
current_ticks = regs.main_counter.full;
|
||||
m_last_ticks = regs.main_counter.full;
|
||||
else
|
||||
{
|
||||
uint32_t current_low = regs.main_counter.low;
|
||||
if (current_low < (uint32_t)m_last_ticks)
|
||||
const uint32_t current_low = regs.main_counter.low;
|
||||
if (current_low < static_cast<uint32_t>(m_last_ticks))
|
||||
m_32bit_wraps++;
|
||||
current_ticks = ((uint64_t)m_32bit_wraps << 32) | current_low;
|
||||
m_last_ticks = (static_cast<uint64_t>(m_32bit_wraps) << 32) | current_low;
|
||||
}
|
||||
m_last_ticks = current_ticks;
|
||||
}
|
||||
|
||||
SystemTimer::get().update_tsc();
|
||||
|
||||
if (should_invoke_scheduler())
|
||||
Processor::scheduler().timer_interrupt();
|
||||
Processor::scheduler().on_timer_interrupt();
|
||||
}
|
||||
|
||||
uint64_t HPET::ms_since_boot() const
|
||||
{
|
||||
auto current = time_since_boot();
|
||||
const auto current = time_since_boot();
|
||||
return current.tv_sec * 1'000 + current.tv_nsec / 1'000'000;
|
||||
}
|
||||
|
||||
uint64_t HPET::ns_since_boot() const
|
||||
{
|
||||
auto current = time_since_boot();
|
||||
const auto current = time_since_boot();
|
||||
return current.tv_sec * 1'000'000'000 + current.tv_nsec;
|
||||
}
|
||||
|
||||
timespec HPET::time_since_boot() const
|
||||
{
|
||||
auto& regs = registers();
|
||||
const auto& regs = registers();
|
||||
|
||||
uint64_t counter = read_main_counter();
|
||||
uint64_t seconds = counter / m_ticks_per_s;
|
||||
uint64_t ticks_this_second = counter % m_ticks_per_s;
|
||||
const uint64_t counter = read_main_counter();
|
||||
const uint64_t seconds = counter / m_ticks_per_s;
|
||||
const uint64_t ticks_this_second = counter % m_ticks_per_s;
|
||||
|
||||
long ns_this_second = ticks_this_second * regs.counter_clk_period / FS_PER_NS;
|
||||
const long ns_this_second = ticks_this_second * regs.counter_clk_period / FS_PER_NS;
|
||||
|
||||
return timespec {
|
||||
.tv_sec = static_cast<time_t>(seconds),
|
||||
@@ -308,7 +339,7 @@ namespace Kernel
|
||||
|
||||
void HPET::pre_scheduler_sleep_ns(uint64_t ns)
|
||||
{
|
||||
auto& regs = registers();
|
||||
const auto& regs = registers();
|
||||
|
||||
const uint64_t target_ticks = BAN::Math::div_round_up<uint64_t>(ns * FS_PER_NS, regs.counter_clk_period);
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace Kernel
|
||||
SystemTimer::get().update_tsc();
|
||||
|
||||
if (should_invoke_scheduler())
|
||||
Processor::scheduler().timer_interrupt();
|
||||
Processor::scheduler().on_timer_interrupt();
|
||||
}
|
||||
|
||||
uint64_t PIT::read_counter_ns() const
|
||||
|
||||
@@ -11,12 +11,24 @@ namespace Kernel
|
||||
|
||||
static SystemTimer* s_instance = nullptr;
|
||||
|
||||
void SystemTimer::initialize(bool force_pic)
|
||||
struct pvclock_vcpu_time_info
|
||||
{
|
||||
uint32_t version;
|
||||
uint32_t pad0;
|
||||
uint64_t tsc_timestamp;
|
||||
uint64_t system_time;
|
||||
uint32_t tsc_to_system_mul;
|
||||
int8_t tsc_shift;
|
||||
uint8_t flags;
|
||||
uint8_t pad[2];
|
||||
};
|
||||
|
||||
void SystemTimer::initialize()
|
||||
{
|
||||
ASSERT(s_instance == nullptr);
|
||||
auto* temp = new SystemTimer;
|
||||
ASSERT(temp);
|
||||
temp->initialize_timers(force_pic);
|
||||
temp->initialize_timers();
|
||||
s_instance = temp;
|
||||
}
|
||||
|
||||
@@ -31,12 +43,12 @@ namespace Kernel
|
||||
return !!s_instance;
|
||||
}
|
||||
|
||||
void SystemTimer::initialize_timers(bool force_pic)
|
||||
void SystemTimer::initialize_timers()
|
||||
{
|
||||
m_rtc = MUST(BAN::UniqPtr<RTC>::create());
|
||||
m_boot_time = BAN::to_unix_time(m_rtc->get_current_time());
|
||||
|
||||
if (auto res = HPET::create(force_pic); res.is_error())
|
||||
if (auto res = HPET::create(); res.is_error())
|
||||
dwarnln("HPET: {}", res.error());
|
||||
else
|
||||
{
|
||||
@@ -59,62 +71,100 @@ namespace Kernel
|
||||
|
||||
void SystemTimer::initialize_tsc()
|
||||
{
|
||||
if (!CPUID::has_invariant_tsc())
|
||||
{
|
||||
dwarnln("CPU does not have an invariant TSC");
|
||||
return;
|
||||
}
|
||||
if (CPUID::has_kvm_pvclock())
|
||||
return initialize_pvclock();
|
||||
if (CPUID::has_invariant_tsc())
|
||||
return initialize_invariant_tsc();
|
||||
dwarnln("No supported TSC based timers available");
|
||||
}
|
||||
|
||||
const uint64_t tsc_freq = get_tsc_frequency();
|
||||
void SystemTimer::initialize_invariant_tsc()
|
||||
{
|
||||
const uint64_t tsc_freq = [this]() -> uint64_t {
|
||||
if (const auto cpuid_freq = CPUID::get_tsc_frequency())
|
||||
return cpuid_freq;
|
||||
|
||||
// take 5x 50 ms samples and use the median value
|
||||
|
||||
constexpr size_t tsc_sample_count = 5;
|
||||
constexpr size_t tsc_sample_ns = 50'000'000;
|
||||
|
||||
uint64_t tsc_freq_samples[tsc_sample_count];
|
||||
for (size_t i = 0; i < tsc_sample_count; i++)
|
||||
{
|
||||
const auto start_ns = m_timer->ns_since_boot();
|
||||
|
||||
const auto start_tsc = __builtin_ia32_rdtsc();
|
||||
while (m_timer->ns_since_boot() < start_ns + tsc_sample_ns)
|
||||
Processor::pause();
|
||||
const auto stop_tsc = __builtin_ia32_rdtsc();
|
||||
|
||||
const auto stop_ns = m_timer->ns_since_boot();
|
||||
|
||||
const auto duration_ns = stop_ns - start_ns;
|
||||
const auto count_tsc = stop_tsc - start_tsc;
|
||||
|
||||
tsc_freq_samples[i] = count_tsc * 1'000'000'000 / duration_ns;
|
||||
}
|
||||
|
||||
BAN::sort::sort(tsc_freq_samples, tsc_freq_samples + tsc_sample_count);
|
||||
|
||||
return tsc_freq_samples[tsc_sample_count / 2];
|
||||
}();
|
||||
|
||||
m_tsc_info = { .invariant = {
|
||||
.shift = 0,
|
||||
.mult = static_cast<uint32_t>((1'000'000'000ull << 32) / tsc_freq),
|
||||
}};
|
||||
m_tsc_type = TSCType::Invariant;
|
||||
Processor::initialize_tsc(m_boot_time);
|
||||
|
||||
dprintln("Initialized invariant TSC ({} Hz)", tsc_freq);
|
||||
|
||||
const uint8_t tsc_shift = 22;
|
||||
const uint64_t tsc_mult = (static_cast<uint64_t>(1'000'000'000) << tsc_shift) / tsc_freq;
|
||||
Processor::initialize_tsc(tsc_shift, tsc_mult, m_boot_time);
|
||||
|
||||
m_has_invariant_tsc = true;
|
||||
}
|
||||
|
||||
uint64_t SystemTimer::get_tsc_frequency() const
|
||||
static pvclock_vcpu_time_info read_pvclock_safe(vaddr_t pvclock_vaddr)
|
||||
{
|
||||
// take 5x 50 ms samples and use the median value
|
||||
|
||||
constexpr size_t tsc_sample_count = 5;
|
||||
constexpr size_t tsc_sample_ns = 50'000'000;
|
||||
|
||||
uint64_t tsc_freq_samples[tsc_sample_count];
|
||||
for (size_t i = 0; i < tsc_sample_count; i++)
|
||||
for (;;)
|
||||
{
|
||||
const auto start_ns = m_timer->ns_since_boot();
|
||||
const volatile auto& pvclock = *reinterpret_cast<const volatile pvclock_vcpu_time_info*>(pvclock_vaddr);
|
||||
|
||||
const auto start_tsc = __builtin_ia32_rdtsc();
|
||||
while (m_timer->ns_since_boot() < start_ns + tsc_sample_ns)
|
||||
Processor::pause();
|
||||
const auto stop_tsc = __builtin_ia32_rdtsc();
|
||||
const auto version = pvclock.version;
|
||||
if (version & 1)
|
||||
continue;
|
||||
|
||||
const auto stop_ns = m_timer->ns_since_boot();
|
||||
pvclock_vcpu_time_info copy;
|
||||
memcpy(©, const_cast<const pvclock_vcpu_time_info*>(&pvclock), sizeof(pvclock_vcpu_time_info));
|
||||
|
||||
const auto duration_ns = stop_ns - start_ns;
|
||||
const auto count_tsc = stop_tsc - start_tsc;
|
||||
|
||||
tsc_freq_samples[i] = count_tsc * 1'000'000'000 / duration_ns;
|
||||
if (pvclock.version == version)
|
||||
return copy;
|
||||
}
|
||||
|
||||
BAN::sort::sort(tsc_freq_samples, tsc_freq_samples + tsc_sample_count);
|
||||
|
||||
return tsc_freq_samples[tsc_sample_count / 2];
|
||||
}
|
||||
|
||||
void SystemTimer::update_tsc() const
|
||||
void SystemTimer::initialize_pvclock()
|
||||
{
|
||||
if (!m_has_invariant_tsc)
|
||||
m_tsc_page = MUST(DMARegion::create(sizeof(pvclock_vcpu_time_info), PageTable::MemoryType::Normal));
|
||||
memset(reinterpret_cast<void*>(m_tsc_page->vaddr()), 0, sizeof(pvclock_vcpu_time_info));
|
||||
|
||||
const uint32_t paddr_hi = m_tsc_page->paddr() >> 32;
|
||||
const uint32_t paddr_lo = m_tsc_page->paddr() & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(paddr_hi), "a"(paddr_lo | 1), "c"(0x4b564d01));
|
||||
|
||||
m_tsc_type = TSCType::PVClock;
|
||||
Processor::initialize_tsc(m_boot_time);
|
||||
|
||||
dprintln("Initialized pvclock");
|
||||
}
|
||||
|
||||
void SystemTimer::update_tsc()
|
||||
{
|
||||
if (m_tsc_type == TSCType::None)
|
||||
return;
|
||||
|
||||
// only update every 100 ms
|
||||
if (++m_timer_ticks < 100)
|
||||
// only update once per second
|
||||
const uint64_t current_ns = Processor::ns_since_boot_tsc();
|
||||
if (current_ns < m_tsc_update_ns)
|
||||
return;
|
||||
m_timer_ticks = 0;
|
||||
m_tsc_update_ns = current_ns + 1'000'000'000;
|
||||
|
||||
Processor::update_tsc();
|
||||
Processor::broadcast_smp_message({
|
||||
@@ -123,28 +173,44 @@ namespace Kernel
|
||||
});
|
||||
}
|
||||
|
||||
uint64_t SystemTimer::ns_since_boot_no_tsc() const
|
||||
SystemTimer::TSCInfo SystemTimer::tsc_info() const
|
||||
{
|
||||
return m_timer->ns_since_boot();
|
||||
switch (m_tsc_type)
|
||||
{
|
||||
case TSCType::None:
|
||||
ASSERT_NOT_REACHED();
|
||||
case TSCType::Invariant:
|
||||
return {
|
||||
.shift = m_tsc_info.invariant.shift,
|
||||
.mult = m_tsc_info.invariant.mult,
|
||||
};
|
||||
case TSCType::PVClock:
|
||||
const auto pvclock = read_pvclock_safe(m_tsc_page->vaddr());
|
||||
return {
|
||||
.shift = pvclock.tsc_shift,
|
||||
.mult = pvclock.tsc_to_system_mul,
|
||||
};
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
uint64_t SystemTimer::ms_since_boot() const
|
||||
{
|
||||
if (!m_has_invariant_tsc)
|
||||
if (m_tsc_type == TSCType::None)
|
||||
return m_timer->ms_since_boot();
|
||||
return Processor::ns_since_boot_tsc() / 1'000'000;
|
||||
}
|
||||
|
||||
uint64_t SystemTimer::ns_since_boot() const
|
||||
{
|
||||
if (!m_has_invariant_tsc)
|
||||
if (m_tsc_type == TSCType::None)
|
||||
return m_timer->ns_since_boot();
|
||||
return Processor::ns_since_boot_tsc();
|
||||
}
|
||||
|
||||
timespec SystemTimer::time_since_boot() const
|
||||
{
|
||||
if (!m_has_invariant_tsc)
|
||||
if (m_tsc_type == TSCType::None)
|
||||
return m_timer->time_since_boot();
|
||||
const auto ns_since_boot = Processor::ns_since_boot_tsc();
|
||||
return {
|
||||
@@ -163,11 +229,18 @@ namespace Kernel
|
||||
return m_timer->pre_scheduler_sleep_ns(ns);
|
||||
}
|
||||
|
||||
void SystemTimer::sleep_ns(uint64_t ns) const
|
||||
void SystemTimer::sleep_for_ns(uint64_t timeout_ns) const
|
||||
{
|
||||
if (ns == 0)
|
||||
const uint64_t base_ns = ns_since_boot();
|
||||
ASSERT(!BAN::Math::will_addition_overflow(base_ns, timeout_ns));
|
||||
Processor::scheduler().block_current_thread(nullptr, base_ns + timeout_ns, nullptr);
|
||||
}
|
||||
|
||||
void SystemTimer::sleep_until_ns(uint64_t waketime_ns) const
|
||||
{
|
||||
if (ns_since_boot() >= waketime_ns)
|
||||
return;
|
||||
Processor::scheduler().block_current_thread(nullptr, ns_since_boot() + ns, nullptr);
|
||||
Processor::scheduler().block_current_thread(nullptr, waketime_ns, nullptr);
|
||||
}
|
||||
|
||||
timespec SystemTimer::real_time() const
|
||||
|
||||
@@ -253,8 +253,9 @@ namespace Kernel
|
||||
BAN::Vector<USBHID::Report> outputs;
|
||||
TRY(gather_collection_reports(collection, outputs, USBHID::Report::Type::Output));
|
||||
|
||||
if (collection.usage_page == 0x01)
|
||||
switch (collection.usage_page)
|
||||
{
|
||||
case 0x01:
|
||||
switch (collection.usage_id)
|
||||
{
|
||||
case 0x02:
|
||||
@@ -273,6 +274,15 @@ namespace Kernel
|
||||
dwarnln("Unsupported generic descript page usage 0x{2H}", collection.usage_id);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0C:
|
||||
switch (collection.usage_id)
|
||||
{
|
||||
case 0x01:
|
||||
report.device = TRY(BAN::RefPtr<USBKeyboard>::create(*this, BAN::move(outputs)));
|
||||
dprintln("Initialized an USB Consumer Control");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TRY(result.push_back(BAN::move(report)));
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace Kernel
|
||||
return to_copy;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> USBJoystick::ioctl_impl(int request, void* arg)
|
||||
BAN::ErrorOr<long> USBJoystick::ioctl_impl(unsigned long request, void* arg)
|
||||
{
|
||||
switch (request)
|
||||
{
|
||||
@@ -217,7 +217,7 @@ namespace Kernel
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
return USBHIDDevice::ioctl(request, arg);
|
||||
return USBHIDDevice::ioctl_impl(request, arg);
|
||||
}
|
||||
|
||||
void USBJoystick::update()
|
||||
|
||||
@@ -56,6 +56,8 @@ namespace Kernel
|
||||
READ_MODIFIER(0xE4, KeyModifier::RCtrl);
|
||||
READ_MODIFIER(0xE2, KeyModifier::LAlt);
|
||||
READ_MODIFIER(0xE6, KeyModifier::RAlt);
|
||||
READ_MODIFIER(0xE3, KeyModifier::LSuper);
|
||||
READ_MODIFIER(0xE7, KeyModifier::RSuper);
|
||||
#undef READ_MODIFIER
|
||||
|
||||
#define READ_TOGGLE(scancode, key_modifier) \
|
||||
@@ -135,15 +137,33 @@ namespace Kernel
|
||||
|
||||
ASSERT(m_keyboard_lock.current_processor_has_lock());
|
||||
|
||||
if (usage_page != 0x07)
|
||||
if (state == 0)
|
||||
return;
|
||||
|
||||
switch (usage_page)
|
||||
{
|
||||
dprintln_if(DEBUG_USB_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page);
|
||||
return;
|
||||
case 0x07:
|
||||
if (usage >= 4 && usage < m_keyboard_state_temp.size())
|
||||
m_keyboard_state_temp[usage] = true;
|
||||
break;
|
||||
case 0x0C:
|
||||
switch (usage)
|
||||
{
|
||||
case 0xE9:
|
||||
m_keyboard_state_temp[0x80] = true;
|
||||
break;
|
||||
case 0xEA:
|
||||
m_keyboard_state_temp[0x81] = true;
|
||||
break;
|
||||
default:
|
||||
dprintln_if(DEBUG_USB_KEYBOARD, "Unsupported consumer page usage {2H}", usage);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dprintln_if(DEBUG_USB_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page);
|
||||
break;
|
||||
}
|
||||
if (!state)
|
||||
return;
|
||||
if (usage >= 4 && usage < m_keyboard_state_temp.size())
|
||||
m_keyboard_state_temp[usage] = state;
|
||||
}
|
||||
|
||||
void USBKeyboard::update()
|
||||
@@ -322,8 +342,10 @@ namespace Kernel
|
||||
s_scancode_to_keycode[0xE3] = keycode_normal(4, 1);
|
||||
s_scancode_to_keycode[0xE2] = keycode_normal(4, 2);
|
||||
s_scancode_to_keycode[0x2C] = keycode_normal(4, 3);
|
||||
s_scancode_to_keycode[0xE6] = keycode_normal(4, 5);
|
||||
s_scancode_to_keycode[0xE4] = keycode_normal(4, 6);
|
||||
s_scancode_to_keycode[0xE6] = keycode_normal(4, 4);
|
||||
s_scancode_to_keycode[0xE7] = keycode_normal(4, 5);
|
||||
s_scancode_to_keycode[0x65] = keycode_normal(5, 6);
|
||||
s_scancode_to_keycode[0xE4] = keycode_normal(4, 7);
|
||||
|
||||
s_scancode_to_keycode[0x52] = keycode_normal(5, 0);
|
||||
s_scancode_to_keycode[0x50] = keycode_normal(5, 1);
|
||||
|
||||
@@ -132,9 +132,12 @@ namespace Kernel
|
||||
, m_lun(lun)
|
||||
, m_block_count(block_count)
|
||||
, m_block_size(block_size)
|
||||
, m_name { 's', 'd', (char)('a' + minor(m_rdev)), '\0' }
|
||||
{
|
||||
m_rdev = scsi_get_rdev();
|
||||
|
||||
strcpy(m_name, "sda");
|
||||
m_name[2] += minor(m_rdev);
|
||||
|
||||
}
|
||||
|
||||
USBSCSIDevice::~USBSCSIDevice()
|
||||
|
||||
@@ -151,7 +151,7 @@ extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info)
|
||||
InterruptController::initialize(cmdline.force_pic);
|
||||
dprintln("Interrupt controller initialized");
|
||||
|
||||
SystemTimer::initialize(cmdline.force_pic);
|
||||
SystemTimer::initialize();
|
||||
dprintln("Timers initialized");
|
||||
|
||||
DevFileSystem::initialize();
|
||||
|
||||
2
ports/.gitignore
vendored
2
ports/.gitignore
vendored
@@ -2,3 +2,5 @@
|
||||
!*/patches/
|
||||
!*/build.sh
|
||||
.installed_ports
|
||||
config.sub
|
||||
*-banan_os-meson.txt
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
NAME='SDL2_image'
|
||||
VERSION='2.8.8'
|
||||
DOWNLOAD_URL="https://github.com/libsdl-org/SDL_image/releases/download/release-$VERSION/SDL2_image-$VERSION.tar.gz#2213b56fdaff2220d0e38c8e420cbe1a83c87374190cba8c70af2156097ce30a"
|
||||
DEPENDENCIES=('SDL2' 'libpng' 'libjpeg' 'libtiff' 'libwebp')
|
||||
DEPENDENCIES=('sdl2-compat' 'libpng' 'libjpeg-turbo' 'libtiff' 'libwebp')
|
||||
|
||||
configure() {
|
||||
cmake --fresh -S . -B build -G Ninja \
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
NAME='SDL2_mixer'
|
||||
VERSION='2.8.1'
|
||||
DOWNLOAD_URL="https://github.com/libsdl-org/SDL_mixer/releases/download/release-$VERSION/SDL2_mixer-$VERSION.tar.gz#cb760211b056bfe44f4a1e180cc7cb201137e4d1572f2002cc1be728efd22660"
|
||||
DEPENDENCIES=('SDL2' 'timidity')
|
||||
DEPENDENCIES=('sdl2-compat' 'timidity')
|
||||
|
||||
configure() {
|
||||
cmake --fresh -S . -B build -G Ninja \
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user