- all languages are configured via cedit.ini (the “edit” button in the “languages” menu)
- build/run/debug commands are also configured via cedit.ini
- new languages can be added via cedit.ini
- zator language has been added
---------
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: #554
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Alexey Ryabov <alex@b00bl1k.ru>
Co-authored-by: 4ds-dev <4ds.dev@gmail.com>
Klavisha takes 11 sectors in IMG, and is included only in RU build.
I propose move it to ISO to free space on IMG and make it more consisntent.
Reviewed-on: #635
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Alexey <alex@b00bl1k.ru>
This PR adds a new enum_ports call to the serial driver's control API that lets user-mode programs list the serial ports currently registered in the system.
It also updates debug output strings, changes the USB FTDI driver's service procedure name, and removes duplicated code from the baud rate calculation.
Reviewed-on: #629
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: Alexey Ryabov <alex@b00bl1k.ru>
The `vfprintf` function is declared in the header files, but is not exported in the library.
Reviewed-on: #634
Co-authored-by: Egor00f <y.yarin@inbox.ru>
Summary: the keepalive handler compared the wrong field against the TCB
state constants, and walked into freed memory when the socket it killed was
released by tcp_disconnect.
Details:
Two independent defects in the same branch of tcp_timer_640ms.
First, the state test read TCP_SOCKET.state. That field is the inherited
SOCKET.state, an SS_* bitmask, not the TCB state machine; comparing it
against TCPS_ESTABLISHED compared a bitmask against an enum and decided
nothing meaningful. The TCB state lives in t_state. The comparison is also
changed from `ja` to `jae`, so only embryonic connections -- those whose
handshake never completed within TCP_time_keep_init -- are torn down here.
A synchronized connection now always falls through to .dont_kill, where it
either gets a keepalive probe (SO_KEEPALIVE set) or simply rearms the timer,
as in BSD. Previously an idle but perfectly healthy connection could be
dropped without the application ever asking for keepalives.
Second, the kill path did
push eax
call tcp_disconnect
pop eax
jmp .loop
and .loop dereferences SOCKET.NextPtr of that socket. But tcp_disconnect
jumps straight to tcp_close for a not-yet-synchronized connection, and
tcp_close calls socket_free -- so NextPtr was read out of freed kernel heap
and the timer thread continued its walk down a dangling pointer. The
successor is now saved before the call and the loop resumes at .check_only,
which is exactly what the timed-wait branch at the end of the same loop
already does.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: #621
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Summary: socket_close() skipped both tcp_disconnect and socket_free for any
TCP socket that was not yet in the SS_ISCONNECTED state, leaking the socket
structure and leaving it on the net_sockets list forever.
Details:
The SS_ISCONNECTED gate in socket_close covered only fully established
connections. A socket closed while in SYN_SENT, SYN_RECEIVED or LISTEN, or
one that never connected at all, fell through to a bare `ret`: it was
neither disconnected nor freed. The 4 KiB socket structure and its two ring
buffers stayed allocated, the socket kept its place on net_sockets, its
timers kept being decremented by tcp_timer_640ms, and SOCKET.TID kept
pointing at a thread that was about to exit. A browser or any other
application that opens connections which fail to establish (refused,
filtered, or simply cancelled by the user) leaked one socket per attempt.
The gate is not needed: tcp_disconnect dispatches on the TCB state itself
and jumps straight to tcp_close -- which calls socket_free -- whenever
t_state is below TCPS_ESTABLISHED. Dropping the test therefore routes the
not-yet-synchronized cases to exactly the cleanup they were missing, and
leaves the established path untouched. The SS_ISDISCONNECTING test is kept,
so a second close() on a socket already shutting down is still a no-op.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: #620
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Summary: tcp_respond clamped the free receive space to 65535 and only then
applied RCV_SCALE, so scaled ACKs and keepalives advertised a window far
smaller than the one actually available.
Подробно:
The window field of a TCP header is 16 bits wide and, when window scaling is
in effect, carries the free space shifted right by RCV_SCALE. The two
operations therefore have to happen in that order: shift first, then clamp
the result to TCP_max_win.
tcp_respond did the opposite. With a receive buffer larger than 64 KiB and
RCV_SCALE = 2, free space of 128 KiB was first cut down to 65535 and then
shifted to 16383, announcing 64 KiB instead of the full 128 KiB. The larger
the buffer and the scale factor, the worse the under-advertisement -- the
window only ever shrank, so the effect was lost throughput rather than
corruption, but it silently defeated window scaling on exactly the responses
that carry the window most often.
tcp_output already gets this right (it compares against TCP_max_win shl
RCV_SCALE before writing the field); tcp_respond now agrees with it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tcp_set_persist takes the socket pointer in eax and uses ebx as a
scratch register to compute the RTO:
mov ebx, [eax + TCP_SOCKET.t_srtt]
shr ebx, 2
add ebx, [eax + TCP_SOCKET.t_rttvar]
shr ebx, 1
mov cl, [eax + TCP_SOCKET.t_rxtshift]
shl ebx, cl
By the time the persist timer is armed ebx therefore holds the timeout
value, not the socket. The flag store nevertheless went through ebx, so
it wrote to the linear address <RTO> + TCP_SOCKET.timer_flags -- an
unmapped low address -- instead of setting timer_flag_persist on the
socket.
Any TCP connection whose peer advertises a zero window takes this path
from tcp_output.enter_persist and faults the kernel:
K : Page fault
K : EBX : 0000000A
K : EIP : 80037DF3 (tcp_set_persist, the flag store)
K : Process - forced terminate PID: 00000005
Observed with NetSurf on a HTTP/2 connection to www.redhat.com, where
twelve multiplexed streams closed the receive window. Store the flag
through eax, which tcpt_rangeset leaves untouched.
Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Summary: the received window scale option was stored into SND_SCALE, which
the connection setup code then immediately overwrote with zero, so every
peer window was interpreted unscaled.
Details:
RFC 1323 negotiation is completed in two places -- the SYN_RECEIVED branch
and the active-open branch of tcp_input. Both do
mov ax, word[ebx + TCP_SOCKET.requested_s_scale]
mov word[ebx + TCP_SOCKET.SND_SCALE], ax
relying on the declared order of the four adjacent bytes SND_SCALE,
RCV_SCALE, requested_s_scale, request_r_scale to move both factors at once.
requested_s_scale, however, was never filled in: the option parser wrote the
peer's shift count into SND_SCALE directly, and that value was then clobbered
by the word move with the zero left in requested_s_scale by socket_alloc.
The result was that SND_SCALE ended up 0 on every connection while
TF_RCVD_SCALE was set, so a peer advertising, say, 64 KiB with a shift of 7
was read as advertising 512 bytes. Sending to any modern host was throttled
to a fraction of the real window.
The parser now stores into requested_s_scale, where the setup code expects
it, and clamps the value to TCP_max_winshift (14) as required by RFC 1323 --
a peer sending a larger shift must not be allowed to make our SND_WND
computation shift out of range.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: #619
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
- Add `bbench` to IMG and System Panel
- Universal benchmark with 17 tests for CPU, graphics, memory and disk
- Tests can be toggled and configured
- Generates derailed reports in HTML
- Remove `MGB` and `FSPEED` from System Panel, move them from IMG to ISO
---------
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: #561
Reviewed-by: bad_Dr3dd0x <1702+bad_dr3dd0x@noreply.localhost>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
For chunked responses HTTP_receive added the whole buffer tail to
content_received every time it consumed a chunkline. When several
chunks arrived in one TCP segment, the same bytes were counted once
per chunkline (observed: content_received = 42 MB for an 83 KB page);
the value only became exact at got_all_data. A client trusting the
counter mid-transfer read far past the buffer and page-faulted.
In plain buffered mode recompute the exact value from the pointers
instead: min(chunk_ptr, write_ptr) - content_ptr, the same formula
.got_all_data_chunked uses. Data below chunk_ptr is decoded and
contiguous; bytes in [chunk_ptr, write_ptr) are still raw (unconsumed
chunkline + partial chunk). Stream/ring modes keep the running add:
there data is consumed as it arrives, so the incremental count is
correct.
---------
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: #569
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Implemented reading filesystems with 64 bit feature for partitions < 16TB (for standard 4kb block size)
Reading support for all ext4 filesystems built with default features.
Mount filesystems with metadata_csum / metadata_csum_seed and check csum, in case it doesn't match the mount fails.
Reviewed-on: #506
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: Matou <mathieubotros@gmail.com>
I wrote an autotest for Netsurf. After 130 test run the system could not
create any new process anymore. Now this is fixed. Result:
916 OK, 0 CRASH, 0 HANG
Futexes (sysfn 77) live in the per-process handle table (PROC.htab)
and are allocated from the kernel's small-object heap via
create_object. The only code path that ever frees one is
destroy_object, which runs solely on an explicit FUTEX_DESTROY call --
and real programs never make it: newlib-based applications create a
dozen or so futexes at startup for their internal locks (malloc,
stdio) and simply exit, expecting the kernel to clean up. Nothing
does: destroy_process tears down HDLLs and page tables but never
walks the handle table.
Each leaked futex pins 48 bytes of the kernel malloc arena, and that
arena is a single fixed 128 KB block (init_malloc has no grow path).
After roughly two thousand leaked handles -- a few hundred to a few
thousand application launches within one uptime -- kernel malloc()
starts failing system-wide. The first visible casualty is
load_library: it can no longer allocate a DLLDESCR, so every dll.obj
load in every new process fails from that point on ("cannot load
library"), which is easy to mistake for a userland problem.
Reproduced by repeatedly launching a newlib application: the arena
filled with ~1750 48-byte chunks carrying the 'FUTX' magic (confirmed
by dumping the live arena; mst.topsize had dropped to 32 bytes with
free physical memory and kernel heap space still abundant), and dll
loading died after ~130 launches.
Fix: in destroy_process, after destroy_all_hdlls, walk the process's
handle table and free every live object. Free slots hold small
free-list indices and the reserved stdin/stdout/stderr handles hold
small values, so a bounds check against OS_BASE skips them; live
slots hold kernel pointers and are additionally verified by the
'FUTX' magic. If other object kinds are ever added to the handle
table, they will need their own destructors here -- the magic check
makes this walk skip them safely rather than crash.
---------
Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: #567
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Co-committed-by: leency <lipatov.kiril@gmail.com>
I wrote an autotest that runs Netsurf a lot of times. While running this
test I always faced the hang issue. First thought was about network
and sockets but QEMU debug through telnet revealed the issue in timers.
Now there is no hang after this fix.
timer_hs and cancel_timer_hs hold the global timer-list lock
(lock_timer_list/unlock_timer_list) across a short critical section
of plain list-pointer stores, without disabling interrupts. If the
owning thread is preempted inside that window, it can never be
scheduled again while a higher-priority thread is runnable: the
scheduler is strictly priority-based and osloop's check_timers (top
priority) busy-waits for the same lock via change_task, which never
descends to a lower-priority ring while its own ring has a runnable
thread. The result is a permanent, whole-system livelock -- not a
one-off race, but a deterministic outcome whenever the preemption
lands inside the section.
Reproduced by driving thousands of blocking TCP connects (each one
calls timer_hs for its connect timeout) through a browser under QEMU,
where interrupts tend to land on translation-block boundaries right
after the lock's cmpxchg. Confirmed via the QEMU monitor: osloop
spinning forever in lock_timer_list while the lock owner sat, fully
preempted, one instruction into timer_hs's critical section.
Fix: wrap the lock/insert-or-remove/unlock sequence in
timer_hs and cancel_timer_hs with pushfd/cli ... popfd, making it
atomic with respect to preemption. The wait loop inside
lock_timer_list is unaffected -- change_task manages IF on its own,
so spinning there with interrupts off cannot itself hang anything.
Reviewed-on: #564
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Co-authored-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Co-committed-by: Kiril Lipatov <lipatov.kiril@gmail.com>