Compare commits

...
Author SHA1 Message Date
Burer ef1eceaa6c data: point the desktop menu to TASKMAN
Check kernel codestyle / Check kernel codestyle (pull_request) Successful in 21s
Test PR / Build (en_US) (pull_request) Successful in 2m56s
Test PR / Build (ru_RU) (pull_request) Successful in 3m1s
Test PR / Build (es_ES) (pull_request) Successful in 3m1s
Assisted-by: Claude:claude-opus-5-5
2026-10-04 09:25:15 +03:00
Burer 3f3770fc57 apps/taskman: add a readme
Check kernel codestyle / Check kernel codestyle (pull_request) Successful in 20s
Test PR / Build (en_US) (pull_request) Successful in 1m51s
Test PR / Build (es_ES) (pull_request) Successful in 1m57s
Test PR / Build (ru_RU) (pull_request) Successful in 2m1s
Assisted-by: Claude:claude-opus-5-5
2026-10-03 22:36:40 +03:00
Burer 9fe9b676c1 data: replace CPU and SYSMON with TASKMAN
Check kernel codestyle / Check kernel codestyle (pull_request) Successful in 24s
Test PR / Build (en_US) (pull_request) Successful in 2m10s
Test PR / Build (es_ES) (pull_request) Successful in 2m16s
Test PR / Build (ru_RU) (pull_request) Successful in 2m23s
Put TASKMAN in the image instead of CPU and SYSMON and point the
menu, the system panel and the KolibriNext dock and desktop to it.

Assisted-by: Claude:claude-opus-5-5
2026-10-03 22:02:00 +03:00
Burer 3110deedd5 kernel: start TASKMAN on Ctrl+Alt+Del
Assisted-by: Claude:claude-opus-5-5
2026-10-03 22:01:59 +03:00
Burer 0486f294ce apps/taskman: add a task manager
One program with five tabs instead of CPU and SYSMON:

- Processes: threads with CPU and memory, sortable; Details, End,
  Run..., system threads on request.
- Performance: CPU, temperature, memory and network graphs; the CPU
  sensor (Intel, AMD, Hygon, VIA, Zhaoxin) or a board chip.
- Disks: partitions with labels, used space of memory disks; Open.
- Drivers: drivers loaded by the kernel; Load...
- Autorun: /sys/settings/autorun.dat, a program turned on or off.

The window and lists follow the system colors; en_US, ru_RU, es_ES.
The kpacked binary fits in 12 sectors.

Assisted-by: Claude:claude-opus-5-5
2026-10-03 22:01:59 +03:00
Leency bd071d588b kernel/net: fix use-after-free on refused TCP connections (#622)
Build system / Build (en_US) (push) Successful in 3m2s
Build system / Build (es_ES) (push) Successful in 3m9s
Build system / Build (ru_RU) (push) Successful in 3m15s
Build system / Publish Images (push) Successful in 11m5s
tcp_input: on RST+ACK in SYN_SENT, unlock the socket mutex before
tcp_drop and leave through .drop_no_socket. tcp_drop frees the socket
and locks that mutex itself, so the network thread hung on it.

Assisted-by: Claude:claude-opus-5
Reviewed-on: #622
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: Kiril Lipatov <lipatov.kiril@gmail.com>
2026-09-29 19:12:30 +00:00
Leency 9ec66b0eba drivers/i8255x: get to work on a real device (#725)
Build system / Build (en_US) (push) Successful in 3m23s
Build system / Build (es_ES) (push) Successful in 3m27s
Build system / Build (ru_RU) (push) Successful in 3m31s
Build system / Publish Images (push) Successful in 11m54s
- the TX reclaim loop in int_handler multiplied sizeof.txfd by itself  (mul eax) instead of by last_tx, so it looked 1024 bytes past tx_ring and never freed a descriptor
- it also left txfd.status set, and transmit treats a non-zero status as busy, so once the 16-entry ring wrapped every send ended in "TX overrun": DHCP fell back to link-local, ping showed "Socket error", while the link still read as connected
- reclaim only descriptors the device completed (TXFD_STATUS_C) and zero their status; transmit now checks for an unreclaimed buffer (virt_addr)

Seen on an EtherExpress Pro/100 in a Pentium II. Reproduced in QEMU (-cpu pentium2, i82557b): ping stopped at the 12th reply every time; with the fix it runs indefinitely, also under a UDP flood.

Reviewed-on: #725
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-29 19:03:24 +00:00
Leency 95bcf78537 kernel/ahci: support CD/DVD drives (ATAPI) (#694)
Build system / Build (es_ES) (push) Successful in 3m34s
Build system / Build (en_US) (push) Successful in 3m39s
Build system / Build (ru_RU) (push) Successful in 3m46s
Build system / Publish Images (push) Successful in 10m4s
Summary: an optical drive on an AHCI port was detected and then ignored,
so CD/DVD only worked with the controller switched to IDE mode. It now
shows up as /srN and ISO9660 discs are readable, including disc changes.

Details:
- ahci_atapi_cmd sends a SCSI command through the ATA PACKET command
  (A bit in the command header, CDB in acmd, DMA when IDENTIFY PACKET
  word 49 allows it, DMADIR when word 62 requires it). Built on top of it:
  TEST UNIT READY, REQUEST SENSE, READ CAPACITY(10), READ(10), READ TOC
  (start of the last session for multisession discs) and START STOP UNIT
  for DISKFUNC.LoadTray.
- Drives are registered as sr0, sr1, ... with DISK_NO_INSERT_NOTIFICATION,
  2048-byte sectors and read-only media; iso9660 mounts them as /srN/1.
  They cannot be named cd*: fs_lfn.inc sends every path starting with "cd"
  to the old ATAPI-over-IDE code.
- Disc change: the kernel lets go of a mounted medium only when querymedia
  fails, so after a UNIT ATTENTION querymedia fails once and the kernel
  immediately mounts the new disc. A READ(10) that hits UNIT ATTENTION
  fails instead of silently reading the new disc.
- One ATAPI transfer is capped at (PRDT_MAX_ENTRIES - 1) * 4096 bytes, so
  the PRDT always covers the whole request. The PRDT builder moved out of
  ahci_rw_sectors into ahci_build_prdt and is shared by both paths.
- A command the drive refuses (an empty tray does that on every TEST UNIT
  READY) restarts the port quietly instead of running the full recovery.
- Optical ports never busy-poll a long command and never switch the whole
  controller to polling: missing interrupts are counted per port and only
  that port's PxIE is turned off.
- Diagnostic output (command statistics, interrupt wakeups, register dumps
  during init) is now behind AHCI_DBGLVL, off by default. Errors and one
  line per detected device are still printed.

Tested: QEMU, VirtualBox and VMware (detection, listings and reads checked
against host checksums; eject/insert in QEMU and VirtualBox, a direct disc
swap in VirtualBox, an empty drive in VMware), SATA disk read/write on the
same controller in QEMU, and a GA-D525TUD (NM10) with an ASUS DRW-24B3ST:
detection, reading, disc change. The debug level change was build-tested
only.

Assisted-by: Claude Opus 5
Reviewed-on: #694
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-29 15:44:06 +00:00
Leency 6f3cae4e0c kernel/network: fix window-update check in tcp_output (#711)
Build system / Build (en_US) (push) Successful in 4m8s
Build system / Build (es_ES) (push) Successful in 3m58s
Build system / Build (ru_RU) (push) Successful in 4m9s
Build system / Publish Images (push) Successful in 11m38s
`tcp_output`: the window-update check computed `min(free, max_win - advertised)` instead of BSD's `min(free, max_win) - advertised`. With unread data in the receive buffer, every `send()` produced an empty ACK and never reached the persist state: no zero-window probes, and the connection hung.

- Clamp to the free space first, then subtract the advertised window.
- Compare signed: the result is negative when the window shrank.

Tested in QEMU with pcap: ~11000 empty ACKs in 0.6 s and no probe before the fix; 12 ACKs and a 1-byte persist probe after it.

Reviewed-on: #711
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-29 13:38:57 +00:00
Leency b59e371c0e kernel/network: forget a network device's state when it is removed (#719)
Build system / Build (en_US) (push) Successful in 5m45s
Build system / Build (es_ES) (push) Successful in 5m55s
Build system / Build (ru_RU) (push) Successful in 6m4s
Build system / Publish Images (push) Failing after 11m50s
- `net_remove_device`: clear the slot's IPv4 settings, ARP table and counters, and drop its frames from the ethernet input queue.
- `ipv4_route`:
  - skip slots without a device;
  - an interface without an address routes broadcasts only;
  - off-link without a gateway fails instead of resolving 0.0.0.0.
- `ipv4_output_raw`: check the route before resolving it.
- `eth_output`, `arp_output_request`: refuse a null device.
- `eth_output`: count a too-large frame on the device, not on `eax`.

Reviewed-on: #719
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-29 13:30:00 +00:00
Leency 939505198f http.obj: close the socket when connect() fails; kernel: unlock on tcp_connect errors
Check kernel codestyle / Check kernel codestyle (pull_request) Successful in 25s
Test PR / Build (ru_RU) (pull_request) Successful in 2m2s
Test PR / Build (en_US) (pull_request) Successful in 2m11s
Test PR / Build (es_ES) (pull_request) Successful in 2m18s
Build system / Build (en_US) (push) Successful in 3m50s
Build system / Build (es_ES) (push) Successful in 3m52s
Build system / Build (ru_RU) (push) Successful in 3m55s
Build system / Publish Images (push) Successful in 11m8s
open_connection in http.obj left the socket open whenever connect()
failed. The kernel never reclaims sockets of a finished process
(socket_process_end is a stub), so every failed connect leaked a socket
with its two SOCKET_BUFFER_SIZE rings for good, and a late SYN+ACK could
still connect the orphan. WebView with a few dead image hosts ran the
kernel heap dry ("SOCKET_ring_create: Out of memory!"), after which every
application lost the network. Close the socket on the way out.

The socket() error check compared against 0, but the syscall returns -1
on failure; compare with -1.

The close() above exposed a second bug: tcp_connect took SOCKET.mutex
before creating the rings and returned from .nomem and .enoroute without
releasing it. Any later socket_free on that socket - close() from the
application, once http.obj does it - then waited for the mutex forever
and the thread became unkillable. Unlock on both error exits.

Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-28 14:38:01 +03:00
Burer 75cb80fd33 ci: compact older builds on the storage server (#697)
Build system / Build (es_ES) (push) Successful in 3m23s
Build system / Build (en_US) (push) Successful in 3m27s
Build system / Build (ru_RU) (push) Successful in 3m28s
Build system / Publish Images (push) Successful in 3m14s
Every push to main publishes 4 images per language plus the unpacked build tree, and nothing on the storage server ever shrinks. `kolibri.raw` is a fixed 128 MiB regardless of content, and `kolibri.img` ends up stored three times per language.

This adds a compaction step at the end of the deploy playbook. It runs on the storage server itself, so nothing extra crosses the network.

- The build that was just published stays as it is: bare images and a browsable tree.
- Every older build keeps its images zipped and loses the unpacked tree, which is rebuildable from the commit anyway.

`*.distr.zip`, `sha256sums.txt` and `build.log` are never touched.

Reviewed-on: #697
Reviewed-by: Gleb Zaharov <risdeveau@lair.moe>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
2026-09-28 07:32:37 +00:00
Burer 6ba901606d ci: open submodule bump PRs as the bot, not as Actions
Test PR / Build (es_ES) (pull_request) Successful in 4m48s
Test PR / Build (en_US) (pull_request) Successful in 5m3s
Test PR / Build (ru_RU) (pull_request) Successful in 2m18s
Build system / Build (ru_RU) (push) Successful in 4m52s
Build system / Build (es_ES) (push) Successful in 5m11s
Build system / Build (en_US) (push) Successful in 5m16s
Build system / Publish Images (push) Successful in 4m8s
A branch pushed and a pull request opened with the built-in GITEA_TOKEN
come from the Actions user, and events it creates start no workflow run.
Test PR never ran on a bump, so the required check stayed missing and
the PRs could not be merged however many approvals they collected.

Put BOT_TOKEN back in both places: checkout persists it for the push,
and the API call needs it to open the PR under the bot account. This
reverts 882f1f024.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-28 07:17:58 +00:00
kolibrios-bot Bot b1d329da2a chore/submodules: bump cmm to 4aeaee3386dac12fc4ef57ad531b632890df5425
Test PR / Build (es_ES) (pull_request) Successful in 2m22s
Test PR / Build (ru_RU) (pull_request) Successful in 2m25s
Test PR / Build (en_US) (pull_request) Successful in 2m27s
Build system / Build (es_ES) (push) Successful in 6m5s
Build system / Build (en_US) (push) Successful in 6m31s
Build system / Build (ru_RU) (push) Successful in 6m35s
Build system / Publish Images (push) Successful in 5m18s
2026-09-28 07:14:00 +00:00
Leency df9946fe80 libs/libimg: make the grayscale JPEG palette opaque
Test PR / Build (en_US) (pull_request) Successful in 1m55s
Test PR / Build (ru_RU) (pull_request) Successful in 2m1s
Test PR / Build (es_ES) (pull_request) Successful in 2m5s
Build system / Build (es_ES) (push) Successful in 2m59s
Build system / Build (en_US) (push) Successful in 3m5s
Build system / Build (ru_RU) (push) Successful in 3m10s
Build system / Publish Images (push) Successful in 3m27s
A grayscale JPEG is decoded as Image.bpp8i with a 256-level gray
palette built from xor eax, eax, so every entry had alpha 0. After
img.convert to Image.bpp32 the picture was fully transparent: programs
that blend by alpha (WebView) reserved its room and drew nothing.
The palette now starts at 0xFF000000, as the PNG decoder fills its own.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-27 20:13:13 +03:00
Leency e3d744f1b5 Clean IMG (#721)
Build system / Build (en_US) (push) Successful in 3m0s
Build system / Build (ru_RU) (push) Successful in 3m6s
Build system / Build (es_ES) (push) Successful in 3m9s
Build system / Publish Images (push) Successful in 3m34s
- Move ImgF to ISO (closed source)
- Move Examples to ISO (any normal app is a better example... and also there is already /sys/example.asm)
- Remove /sys/settings/kolibri.lbl as unnecessary
- Kpack /sys/settings/keymap.key (this is a binnary file so no matter, -2.5KB) and load it by 68.27

Reviewed-on: #721
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-26 17:29:42 +00:00
igorshandIgor Shutrov 8ca3758efb apps/ftpd: bound the pasv port search (#710)
Build system / Build (es_ES) (push) Successful in 3m36s
Build system / Build (ru_RU) (push) Successful in 3m37s
Build system / Build (en_US) (push) Successful in 3m38s
Build system / Publish Images (push) Successful in 3m2s
On a failed bind cmdPASV jumped straight back to .next_port, and
nextpasvport wraps within [start, end], so a range with no usable port
spun forever without reading the control connection again: the client
hangs.

Count the ports in the range (end - start + 1), decrement after a
failed bind and give up at zero, then close the listener, reset the
state and answer 425 Can't open data connection. The counter lives in a
new thread_data field rather than a register, because mcall bind
clobbers eax/ebx/ecx/edx/esi/edi and esi already carries the sockaddr
length for bind. Decrementing after the failed bind and not before the
next attempt is what keeps a single-port range (start = end) working:
it still gets its one attempt.

Also validate the pair read from the ini. With start > end the range
degenerates and no port is bindable, so fall back to 2000/5000.

---------

Co-authored-by: Igor Shutrov <kolibridev@inbox.ru>
Reviewed-on: #710
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: Igor shutrov <kolibridev@mail.ru>
2026-09-25 09:17:16 +00:00
Leency 02916ed0ee drivers/i2chid: reset a pad stuck on one frame, bring-up ladder only in debug builds
Test PR / Build (es_ES) (pull_request) Successful in 1m58s
Test PR / Build (ru_RU) (pull_request) Successful in 2m5s
Test PR / Build (en_US) (pull_request) Successful in 2m9s
Build system / Build (en_US) (push) Successful in 3m5s
Build system / Build (es_ES) (push) Successful in 3m8s
Build system / Build (ru_RU) (push) Successful in 3m15s
Build system / Publish Images (push) Successful in 3m28s
Assisted-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 10:01:16 +00:00
IgorAandBurer 873d4de379 apps/animage: attempt to fix the scrollbar (#715)
Build system / Build (en_US) (push) Successful in 3m8s
Build system / Build (es_ES) (push) Successful in 3m17s
Build system / Build (ru_RU) (push) Successful in 3m20s
Build system / Publish Images (push) Successful in 4m11s
- replace the hand drawn scrollbars with the box_lib widget
- separate start and minimal window size, enforce minimal on resize
- use the libimg and box_lib import lists instead of hand written ones
- use the process_information struct for procinfo
- drop the dead sound handler and the unused palette offset
- bump version to 1.53

---------

Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: #715
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: IgorA <aie85playm@gmail.com>
2026-09-24 08:27:25 +00:00
Leency b2f9cc9809 kpack: add native Windows and Linux ports (#696)
Build system / Build (es_ES) (push) Successful in 2m53s
Build system / Build (en_US) (push) Successful in 3m1s
Build system / Build (ru_RU) (push) Successful in 3m5s
Build system / Publish Images (push) Successful in 3m29s
Windowless in-place compressor (kpackw.exe / kpackl), reusing the
original LZMA + kerpack sources; auto-detects kernel.mnt. Tupfile builds both.

Assisted-by: Claude Opus 5
Reviewed-on: #696
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: IgorA <22+igora@noreply.localhost>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-23 22:48:55 +00:00
Leency 298155191d apps/tinypad: fix select all delete crash (fix #173) (#700)
Build system / Build (es_ES) (push) Successful in 3m2s
Build system / Build (en_US) (push) Successful in 3m9s
Build system / Build (ru_RU) (push) Successful in 3m11s
Build system / Publish Images (push) Successful in 3m24s
fixes both issues in #173

Reviewed-on: #700
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: IgorA <22+igora@noreply.localhost>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-23 20:19:17 +00:00
Burer 49b8cdcd54 ci: mark submodule contents dirty after a bump
Test PR / Build (es_ES) (pull_request) Successful in 2m5s
Test PR / Build (ru_RU) (pull_request) Successful in 2m7s
Test PR / Build (en_US) (pull_request) Successful in 2m14s
Build system / Build (es_ES) (push) Successful in 12m10s
Build system / Build (ru_RU) (push) Successful in 12m13s
Build system / Build (en_US) (push) Successful in 12m17s
Build system / Publish Images (push) Successful in 3m33s
git diff reports a submodule bump as a bare gitlink, so the files inside
kept their cached ctime alignment and tup never rebuilt them.
2026-09-22 21:28:30 +03:00
Egor00f c121db7a88 libc.obj: use bitfield flags in file instead of int variables && rewrite freopen, fopen (#691)
Build system / Build (es_ES) (push) Successful in 3m18s
Build system / Build (en_US) (push) Successful in 3m23s
Build system / Build (ru_RU) (push) Successful in 3m25s
Build system / Publish Images (push) Successful in 4m52s
Use bitfield `flags` flags in file instead of `int` variables `mode`, `error`, `eof`.

And rewrite weird logic opening/close files

Reviewed-on: #691
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Co-authored-by: Egor00f <y.yarin@inbox.ru>
2026-09-22 12:39:50 +00:00
Egor00f 9527a0f3d1 libshell & shell: implement a return value for the shell API (#660)
Build system / Build (en_US) (push) Successful in 3m35s
Build system / Build (es_ES) (push) Successful in 3m29s
Build system / Build (ru_RU) (push) Successful in 3m29s
Build system / Publish Images (push) Successful in 4m41s
Require: #657 ([compare](https://git.kolibrios.org/Egor00f/kolibrios/compare/update-shell-api...shell-api-implement-return-value))

Implement a return value for shell API functions.
required for updating libc streams.

The return value is declared after `data` for consistency with older programs.

# Changes:
## [`shell`](https://git.kolibrios.org/KolibriOS/kolibrios/pulls/660/files#diff-9e9982c0c3e401531fcfbc1f9dd5f1f3d85452fd)
+ `SHELL_PUTS` and `SHELL_GETS` return the number of bytes written
+ `SHELL_GETC` write full `int` value
## `libshell`
+ [`shell_gets`](https://git.kolibrios.org/KolibriOS/kolibrios/pulls/660/files#diff-8840a9f9a5e28f05f5f46e1b5106caf3ce6c470e) returns `NULL` or `EOF`, or a pointer to a string and returns the number of bytes received
+ [`shell_getc`](https://git.kolibrios.org/KolibriOS/kolibrios/pulls/660/files#diff-955a257b2a02cfc5ee9879b7efc50d0644ad179c) return `int`
+ [`shell_printf`](https://git.kolibrios.org/KolibriOS/kolibrios/pulls/660/files#diff-4ffb653a63ef098530e336370053615fee66be03) returns the number of bytes written
+ [`shell_puts`](https://git.kolibrios.org/KolibriOS/kolibrios/pulls/660/files#diff-ee4df9617f16bc52153701c0edc6c2947dd877a8) returns the number of bytes written
+ [`shell_write_string`](https://git.kolibrios.org/KolibriOS/kolibrios/pulls/660/files#diff-cebe23f17158adc73d20c5f9096862c209732598) returns the number of bytes written

Reviewed-on: https://git.kolibrios.org/KolibriOS/kolibrios/pulls/660
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
2026-09-22 10:01:06 +00:00
Leency 1e05d19c4c kernel/disk: release the partition scan buffer with kernel_free (#695)
Build system / Build (es_ES) (push) Successful in 2m59s
Build system / Build (en_US) (push) Successful in 3m3s
Build system / Build (ru_RU) (push) Successful in 3m7s
Build system / Publish Images (push) Successful in 3m20s
Summary: disk_scan_partitions takes its three-sector buffer from
kernel_alloc but gave it back with the malloc heap's free, which reads a
chunk header that a kernel_alloc block does not have. Mounting a disk
with non-512-byte sectors could fault or corrupt the malloc heap.

Details:
The global mbr_buffer is used only for 512-byte sectors and only while no
other scan holds it; every other case allocates the buffer with
kernel_alloc. The release path still called free, the malloc heap
function: it looks at [ptr-8] for the chunk head. A kernel_alloc block is
page-aligned, so that is the tail of the previous page - a page fault when
that page is not mapped, otherwise a bogus header and possibly a damaged
heap.

Since "disk cache: support for sector sizes other than 512 bytes"
(9d022746f) every CD/DVD mount takes this path, so it is no longer a rare
race of two scans. It was hit as a page fault in free+0xF called from
disk_scan_partitions while an AHCI optical drive remounted a changed disc
in QEMU.

kernel_free keeps ebx and esi; the only caller, disk_media_changed, saves
ebx, esi and edi itself, so replacing the call does not disturb it.

Tested: kernel builds; in QEMU a CD on an AHCI port was mounted at boot and
remounted after swapping discs A -> B -> A, without faults, with this change
on top of origin/main and the AHCI ATAPI support branch.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: #695
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-20 09:49:44 +00:00
Matou1306 ecdebae231 Kernel/fs: Add symlink flag to sysfunc70 and update the English documentation (#656)
Build system / Build (en_US) (push) Successful in 2m57s
Build system / Build (es_ES) (push) Successful in 2m59s
Build system / Build (ru_RU) (push) Successful in 3m3s
Build system / Publish Images (push) Successful in 4m44s
Used in 70.1 and 70.5 in the ext driver

Reviewed-on: #656
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: Matou1306 <mathieubotros@gmail.com>
2026-09-20 04:46:24 +00:00
0150178c90 ftpd: actually close the passive listening socket (#707)
Build system / Build (es_ES) (push) Successful in 3m15s
Build system / Build (ru_RU) (push) Successful in 3m20s
Build system / Build (en_US) (push) Successful in 3m26s
Build system / Publish Images (push) Successful in 4m26s
mcall close takes the socket number in ecx, but the operand was
commented out in the two places that close the PASV listener, so close
ran with whatever ecx happened to hold. Both call sites had just put the
listener in ecx, so the socket was closed by accident: the code worked
only as long as that accident held. The cmdPASV cleanup was commented
out completely, so a second PASV before the client connected left the
previous listener open.

Restore the operand in threadloop (ftpd.asm) and in open_datasock, and
re-enable the cmdPASV prologue, which also resets passivesocknum to -1.

Closing the data socket needed the same care: datasocketnum only holds
a live socket in MODE_PASSIVE_OK and MODE_ACTIVE, so the new
close_data_sock helper closes it in those two states only. The
.cannot_open label is also reachable before open_datasock runs (the
length checks at the top of cmdSTOR), where datasocketnum is either
stale or never initialised, and closing it unconditionally there could
have closed an unrelated socket that had reused the number. The field
is now initialised to -1 at thread start and reset to -1 after every
close.

---------

Co-authored-by: leency <lipatov.kiril@gmail.com>
Co-authored-by: Igor Shutrov <kolibridev@inbox.ru>
Reviewed-on: #707
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: igorsh <kolibridev@mail.ru>
2026-09-19 23:45:35 +00:00
3caf2a7a72 apps/ftpd: truncate the file on STOR instead of overwriting in place (#706)
Build system / Build (es_ES) (push) Successful in 2m50s
Build system / Build (en_US) (push) Successful in 2m53s
Build system / Build (ru_RU) (push) Successful in 3m1s
Build system / Publish Images (push) Successful in 3m40s
cmdSTOR opens the destination with O_CREATE + O_WRITE, and libio only
truncates on write when the position is already at EOF (libio.asm:314),
which never happens here. Replacing a longer file with a shorter one
therefore kept the old tail: 4096-byte A overwritten by 1024-byte B
produced a 4096-byte file holding B followed by A[1024:4096], and
overwriting with zero bytes left the file completely untouched.

Call file.truncate (SF 70.4, size = Position = 0) right after a
successful open so that STOR replaces the file, as RFC 959 requires.
The descriptor survives the call in ebx because sendFTP clobbers the
registers. A failed truncate closes the descriptor and answers 550
through a new .truncate_error path.

The libio import list gains file_truncate, exported since 2009.

-------------------------

STOR: усекать файл при перезаписи, чтобы не оставался старый хвост

Проблема

cmdSTOR открывает целевой файл с O_CREATE + O_WRITE, а libio усекает файл при записи только если позиция уже находится в EOF (libio.asm:314). В этом сценарии условие никогда не выполняется. Поэтому при замене длинного файла коротким сохранялся старый хвост: 4096-байтный A, перезаписанный 1024-байтным B, давал 4096-байтный файл, содержащий B, а затем A[1024:4096]. Перезапись нулевым количеством байт вообще не изменяла файл.

Решение

Сразу после успешного открытия вызывается file.truncate (SF 70.4, size = Position = 0), чтобы STOR заменял файл, как требует RFC 959. Дескриптор сохраняется в ebx после вызова, так как sendFTP затирает регистры. Если truncate завершается ошибкой, дескриптор закрывается, а ответ 550 отправляется через новый обработчик .truncate_error.

Дополнительно

В список импортов libio добавлен file_truncate (экспортируется с 2009 года).
Co-authored-by: leency <lipatov.kiril@gmail.com>
Co-authored-by: Igor Shutrov <kolibridev@inbox.ru>
Reviewed-on: #706
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: igorsh <kolibridev@mail.ru>
2026-09-19 16:56:31 +00:00
Leency 019f2629dc apps/cedit: do not free the menu canvas from another thread (fix #636) (#702)
Build system / Build (en_US) (push) Successful in 3m9s
Build system / Build (es_ES) (push) Successful in 3m13s
Build system / Build (ru_RU) (push) Successful in 3m23s
Build system / Publish Images (push) Successful in 6m10s
Fixes #636

**Причина.** Каждое меню работает в своём потоке и рисует себя из холста `m.canvas`. Этот холст освобождал (`G.destroy`) не только сам поток меню, но и другие потоки:
- `Menu.close()` вызывается из главного потока и при переключении подменю. Он освобождал холст до `K.ExitID()`.
- При срабатывании шортката из подменю холст родительского меню освобождал поток-потомок.

При быстрых кликах поток меню в этот момент как раз внутри `DrawCanvas` (sysfn 65). Ядро читает из уже освобождённого буфера и получает page fault в режиме ядра, поэтому в логе CS=8. Кроме того, если поток сам выходил через `exit`/`escape` одновременно с чужим `close()`, получался двойной free.

**Исправление.** В [Menu.ob07](develop/cedit/SRC/Menu.ob07) убрал все четыре `G.destroy` для холста меню: в `exit`, `escape`, `close` и в ветке шорткатов. Холст и так создаётся лениво в `open()` при `m.canvas = NIL`. Меню создаются один раз при старте, и размер у них не меняется, так что холст теперь живёт всё время работы программы. Утечки нет, и кроме того больше нет выделения и освобождения памяти при каждом открытии меню.

Reviewed-on: #702
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Alexey Ryabov <alex@b00bl1k.ru>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-18 22:07:28 +00:00
Gitea Actionsandkolibrios-bot Bot 63ee53f4a3 chore/submodules: bump cmm_apps to upstream (#698)
Build system / Build (ru_RU) (push) Successful in 4m4s
Build system / Build (es_ES) (push) Successful in 4m4s
Build system / Build (en_US) (push) Successful in 4m7s
Build system / Publish Images (push) Successful in 3m30s
Co-authored-by: kolibri-bot <bot@kolibrios.org>
Reviewed-on: #698
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: Gitea Actions <-2+gitea-actions@noreply.localhost>
2026-09-18 12:09:51 +00:00
IgorA 7c8eba2ed4 libs/sort: cleared the DF flag for safety reasons (#704)
Build system / Build (es_ES) (push) Successful in 3m2s
Build system / Build (ru_RU) (push) Successful in 3m9s
Build system / Build (en_US) (push) Successful in 3m13s
Build system / Publish Images (push) Successful in 5m23s
Reviewed-on: #704
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: IgorA <aie85playm@gmail.com>
2026-09-18 11:44:46 +00:00
99 changed files with 7537 additions and 576 deletions

No files matched your search

+24
View File
@@ -54,3 +54,27 @@
src: "{{ stable_artifact_path }}/"
dest: "{{ storage_path }}/../"
mode: preserve
# older builds shrink to compressed images and lose their unpacked tree; the newest few keep both
- name: Looking for zstd on the storage server
ansible.builtin.shell: command -v zstd
register: zstd_present
changed_when: false
failed_when: false
- name: Requiring zstd for compaction
ansible.builtin.assert:
that: zstd_present.rc == 0
fail_msg: >-
zstd is not installed on the storage server, so older builds cannot
be compacted. Install it and re-run this build.
- name: Compacting older builds
ansible.builtin.script:
cmd: >-
../../utils/compact-builds.sh
{{ storage_path | quote }}
{{ compact_keep | default(5) | int }}
{{ compact_max | default(10) | int }}
register: compaction
changed_when: "'compacted 0 of' not in compaction.stdout"
+74
View File
@@ -0,0 +1,74 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: 2026 KolibriOS team
# Shrink older builds on the storage server: compress their images and drop
# their unpacked tree, which is rebuildable from the commit. sha256sums.txt
# keeps naming the bare images, so a compacted build has to be decompressed
# before it can be verified.
#
# Layout: <root>/<version>/<lang>/kolibrios-<descr>-<lang>.{img,iso,raw} -> .zst
# <root>/<version>/<lang>/data/ -> removed
#
# Usage: compact-builds.sh <storage-root> [keep] [max-per-run]
# DRY_RUN=1 walks the same selection and changes nothing
set -euo pipefail
root=${1:?storage root required}
# the build just published is always among these, so an upload in flight is safe
keep=${2:-5}
# a build is hundreds of MiB to re-compress: cap the first pass over the backlog
max=${3:-10}
dry=${DRY_RUN:-0}
verb=compacted
[ "$dry" = 1 ] && verb="would compact"
# --rm drops the source only once the archive is written; the box serves the
# site over NFS, so compaction yields to it
compress_image() {
nice -n 10 ionice -c3 zstd -12 -T1 -q --rm "$1"
}
export -f compress_image
leftovers() {
local build=$1
find "$build" -mindepth 2 -maxdepth 2 \
\( -type d -name data \
-o -type f \( -name '*.img' -o -name '*.iso' -o -name '*.raw' \) \) \
-print -quit
}
compacted=0
pending=0
while IFS= read -r version; do
dir="$root/$version"
[ -n "$(leftovers "$dir")" ] || continue
pending=$((pending + 1))
[ "$compacted" -lt "$max" ] || continue
if [ "$dry" = 1 ]; then
compacted=$((compacted + 1))
echo "$verb $version"
continue
fi
# a build holds nine images: one per core, each zstd kept to one thread so
# the two levels of parallelism do not fight. Archive before dropping the
# tree, so a failure here leaves the build merely uncompacted and the next
# run picks it up again
find "$dir" -mindepth 2 -maxdepth 2 -type f \
\( -name '*.img' -o -name '*.iso' -o -name '*.raw' \) -print0 \
| xargs -0 -r -P "$(nproc)" -I{} bash -c 'compress_image "$@"' _ {}
find "$dir" -mindepth 2 -maxdepth 2 -type d -name data -exec rm -rf {} +
compacted=$((compacted + 1))
echo "$verb $version"
# <tag>-<commit count>-g<sha>: order by the count, never by mtime
done < <(find "$root" -mindepth 1 -maxdepth 1 -type d -name '*-*-g*' -printf '%f\n' \
| sort -t- -k2,2n | head -n "-$keep")
echo "$verb $compacted of $pending older build(s), $((pending - compacted)) left for the next run"
+6 -1
View File
@@ -128,7 +128,8 @@ jobs:
fi
# cache restore resets ctimes; realign tup DB to skip a full rebuild,
# but keep files changed since the cache's commit dirty so tup rebuilds them
# but keep files changed since the cache's commit dirty so tup rebuilds them.
# A submodule bump diffs as a bare gitlink, so expand it to its whole subtree
- name: Sync tup DB with filesystem ctime
if: steps.check-tup-cache.outputs.cache_restored == 'true'
run: |
@@ -136,6 +137,10 @@ jobs:
BASE=$(cat .tup/build-commit 2>/dev/null || true)
if [ -n "$BASE" ] && git cat-file -e "${BASE}^{commit}" 2>/dev/null; then
git -c core.quotePath=false diff --name-only "$BASE" HEAD > "$DIRTY"
git diff --raw "$BASE" HEAD | awk '$2 == "160000" { print $NF }' |
while read -r sub; do
git -C "$sub" -c core.quotePath=false ls-files | sed "s|^|$sub/|"
done >> "$DIRTY"
echo "Cache built at $BASE; $(wc -l < "$DIRTY") changed files kept dirty"
python3 .gitea/utils/sync-tup-ctime.py .tup/db "$DIRTY"
else
+2 -1
View File
@@ -34,10 +34,11 @@ jobs:
uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.BOT_TOKEN }}
- name: Bump ${{ matrix.name }} and open PR
env:
TOKEN: ${{ secrets.GITEA_TOKEN }}
TOKEN: ${{ secrets.BOT_TOKEN }}
API: ${{ github.api_url }}
REPO: ${{ github.repository }}
NAME: ${{ matrix.name }}
+21 -20
View File
@@ -41,10 +41,6 @@ img_files = {
{"LIB/KMENU.OBJ", "common/lib/kmenu.obj"},
{"LIB/PIXLIB.OBJ", "common/lib/pixlib.obj"},
{"MEDIA/AC97SND", "common/media/ac97snd"},
{"MEDIA/IMGF/IMGF", "common/media/ImgF/ImgF"},
{"MEDIA/IMGF/CEDG.OBJ", "common/media/ImgF/cEdg.obj"},
{"MEDIA/IMGF/DITHER.OBJ", "common/media/ImgF/dither.obj"},
{"MEDIA/IMGF/INVSOL.OBJ", "common/media/ImgF/invSol.obj"},
{"NETWORK/FTPC.INI", SRC_PROGS .. "/network/ftpc/ftpc.ini"},
{"NETWORK/FTPD.INI", "common/network/ftpd.ini"},
{"NETWORK/KNMAP", "common/network/knmap"},
@@ -58,8 +54,7 @@ img_files = {
{"SETTINGS/FB2READ.INI", "common/settings/fb2read.ini"},
{"SETTINGS/HA.CFG", SRC_PROGS .. "/other/ha/SETTINGS/HA.CFG"},
{"SETTINGS/ICON.INI", build_type .. "/settings/icon.ini"},
{"SETTINGS/KEYMAP.KEY", SRC_PROGS .. "/system/taskbar/KEYMAP.KEY"},
{"SETTINGS/KOLIBRI.LBL", build_type .. "/settings/kolibri.lbl"},
{"SETTINGS/KEYMAP.KEY", VAR_PROGS .. "/system/taskbar/keymap.key.kpack"},
{"SETTINGS/LANG.INI", build_type .. "/settings/lang.ini"},
{"SETTINGS/MENU.DAT", build_type .. "/settings/menu.dat"},
{"SETTINGS/NETWORK.INI", "common/settings/network.ini"},
@@ -273,6 +268,10 @@ extra_files = {
{"kolibrios/lib/i915_dri.drv", "common/lib/i915_dri.drv"},
{"kolibrios/media/fplay", "common/media/fplay"},
{"kolibrios/media/fplay_run", "common/media/fplay_run"},
{"kolibrios/media/ImgF/ImgF", "common/media/ImgF/ImgF"},
{"kolibrios/media/ImgF/cEdg.obj", "common/media/ImgF/cEdg.obj"},
{"kolibrios/media/ImgF/dither.obj", "common/media/ImgF/dither.obj"},
{"kolibrios/media/ImgF/invSol.obj", "common/media/ImgF/invSol.obj"},
{"kolibrios/media/minimp3", "common/media/minimp3"},
{"kolibrios/media/updf", SRC .. "/contrib/media/updf/build/uPDF"},
{"kolibrios/media/vttf", "common/media/vttf"},
@@ -422,7 +421,6 @@ tup.append_table(img_files, {
{"CALENDAR", VAR_PROGS .. "/system/calendar/calendar"},
{"COLRDIAL", VAR_PROGS .. "/system/colrdial/color_dialog"},
{"CROPFLAT", VAR_PROGS .. "/system/cropflat/cropflat"},
{"CPU", VAR_PROGS .. "/system/cpu/cpu"},
{"CPUID", VAR_PROGS .. "/testing/cpuid/CPUID"},
{"DOCPACK", VAR_PROGS .. "/system/docpack/docpack"},
{"DEFAULT.SKN", VAR_SKINS .. "/../skins/Leency/Shkvorka/Shkvorka.skn"},
@@ -447,6 +445,7 @@ tup.append_table(img_files, {
{"SCRSHOOT", VAR_PROGS .. "/media/scrshoot/scrshoot"},
{"SETUP", VAR_PROGS .. "/system/setup/setup"},
{"SKINCFG", VAR_PROGS .. "/system/skincfg/skincfg"},
{"TASKMAN", VAR_PROGS .. "/system/taskman/taskman"},
{"TERMINAL", VAR_PROGS .. "/system/terminal/terminal"},
{"TEST", VAR_PROGS .. "/testing/protection/test"},
{"TINYPAD", VAR_PROGS .. "/develop/tinypad/tinypad"},
@@ -487,11 +486,6 @@ tup.append_table(img_files, {
{"DEVELOP/MTDBG", VAR_PROGS .. "/develop/mtdbg/mtdbg"},
{"DEVELOP/MSTATE", VAR_PROGS .. "/develop/mstate/mstate"},
{"DEVELOP/SCANCODE", VAR_PROGS .. "/develop/scancode/scancode"},
{"DEVELOP/EXAMPLES/CIRCLE", VAR_PROGS .. "/develop/examples/circle/circle"},
{"DEVELOP/EXAMPLES/COLORREF", VAR_PROGS .. "/demos/colorref/colorref"},
{"DEVELOP/EXAMPLES/CONGET", VAR_PROGS .. "/develop/libraries/console_coff/examples/test_gets"},
{"DEVELOP/EXAMPLES/CSLIDE", VAR_PROGS .. "/demos/cslide/cslide"},
{"DEVELOP/EXAMPLES/THREAD", VAR_PROGS .. "/develop/examples/thread/thread"},
{"File Managers/KFAR", VAR_PROGS .. "/fs/kfar/kfar"},
{"File Managers/OPENDIAL", VAR_PROGS .. "/fs/opendial/opendial"},
{"LOD", VAR_PROGS .. "/fs/lod/lod"},
@@ -652,20 +646,28 @@ tup.append_table(extra_files, {
{"kolibrios/3D/blocks/block.bin", VAR_PROGS .. "/bcc32/games/blocks/block.bin"},
{"kolibrios/develop/tcc/lib/crt0.o", VAR_PROGS .. "/develop/ktcc/bin/lib/crt0.o", group = "../programs/develop/ktcc/<crt0.o>"},
{"kolibrios/develop/tcc/lib/tiny.o", VAR_PROGS .. "/develop/ktcc/bin/lib/tiny.o", group = "../programs/develop/ktcc/<tiny.o>"},
{"kolibrios/develop/tcc/lib/libsound.a", VAR_PROGS .. "/develop/ktcc/bin/lib/libsound.a", group = "../programs/develop/ktcc/<libsound.a>"}
{"kolibrios/develop/tcc/lib/libsound.a", VAR_PROGS .. "/develop/ktcc/bin/lib/libsound.a", group = "../programs/develop/ktcc/<libsound.a>"},
{"kolibrios/develop/examples/circle", VAR_PROGS .. "/develop/examples/circle/circle"},
{"kolibrios/develop/examples/colorref", VAR_PROGS .. "/demos/colorref/colorref"},
{"kolibrios/develop/examples/conget", VAR_PROGS .. "/develop/libraries/console_coff/examples/test_gets"},
{"kolibrios/develop/examples/cslide", VAR_PROGS .. "/demos/cslide/cslide"},
{"kolibrios/develop/examples/thread", VAR_PROGS .. "/develop/examples/thread/thread"}
})
-- For russian build, add russian-only programs.
if build_type == "ru_RU" then tup.append_table(img_files, {
{"DEVELOP/EXAMPLES/TESTCON2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_rus"},
}) else tup.append_table(img_files, {
{"DEVELOP/EXAMPLES/TESTCON2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_eng"},
}) end
-- -- For russian build, add russian-only programs.
-- if build_type == "ru_RU" then tup.append_table(img_files, {
-- {"DEVELOP/EXAMPLES/TESTCON2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_rus"},
-- }) else tup.append_table(img_files, {
-- {"DEVELOP/EXAMPLES/TESTCON2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_eng"},
-- }) end
if build_type == "ru_RU" then tup.append_table(extra_files, {
{"kolibrios/develop/examples/testcon2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_rus"},
{"kolibrios/utils/period", VAR_PROGS .. "/other/period/period"},
{"kolibrios/games/Dungeons/Dungeons", VAR_PROGS .. "/games/Dungeons/Dungeons"},
{"kolibrios/games/klavisha/klavisha", VAR_PROGS .. "/games/klavisha/klavisha"},
{"kolibrios/games/klavisha/basekurs.kla", "ru_RU/games/basekurs.kla"},
}) else tup.append_table(extra_files, {
{"kolibrios/develop/examples/testcon2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_eng"},
}) end
end -- tup.getconfig('NO_FASM') ~= 'full'
@@ -692,7 +694,6 @@ tup.append_table(img_files, {
{"BBENCH", VAR_PROGS .. "/cmm/bbench/bbench.com"},
{"SEARCH", VAR_PROGS .. "/cmm/misc/search.com"},
{"SYSPANEL", VAR_PROGS .. "/cmm/misc/software_widget.com"},
{"SYSMON", VAR_PROGS .. "/cmm/sysmon/sysmon.com"},
{"TMPDISK", VAR_PROGS .. "/cmm/tmpdisk/tmpdisk.com"},
{"DEVELOP/CLIPVIEW", VAR_PROGS .. "/cmm/clipview/clipview.com"},
{"DEVELOP/MENU", VAR_PROGS .. "/cmm/menu/menu.com"},
+1 -1
View File
@@ -1 +1 @@
[@]␍location=3␍fsize=0␍ashow=1␍␍[AppPlus]␍path=/sys/app_plus␍param=␍icon=27␍␍$=1␍␍[KFAR]␍path=/sys/file managers/kfar␍param=␍icon=16␍␍[Pixie2]␍path=/sys/media/pixie␍param=␍icon=65␍␍[IconEdit]␍path=/sys/media/iconedit␍param=␍icon=98␍␍[Calc]␍path=/sys/calc␍param=␍icon=4␍␍[Notes]␍path=/kolibrios/utils/notes␍param=␍icon=117␍␍[Dictionary]␍path=/kolibrios/utils/dicty.kex␍param=␍icon=79␍␍[FB2Read]␍path=/sys/fb2read␍param=␍icon=44␍␍[Animage]␍path=/sys/media/animage␍param=␍icon=15␍␍[RDSave]␍path=/sys/rdsave␍param=␍icon=17␍␍$=1␍␍[Volume]␍path=/sys/@volume␍param=␍icon=64␍␍[NetStatus]␍path=/sys/network/netstat␍param=␍icon=33␍␍[SysMon]␍path=/sys/sysmon␍param=␍icon=57␍␍[SysPanel]␍path=/sys/syspanel␍param=␍icon=6
[@]␍location=3␍fsize=0␍ashow=1␍␍[AppPlus]␍path=/sys/app_plus␍param=␍icon=27␍␍$=1␍␍[KFAR]␍path=/sys/file managers/kfar␍param=␍icon=16␍␍[Pixie2]␍path=/sys/media/pixie␍param=␍icon=65␍␍[IconEdit]␍path=/sys/media/iconedit␍param=␍icon=98␍␍[Calc]␍path=/sys/calc␍param=␍icon=4␍␍[Notes]␍path=/kolibrios/utils/notes␍param=␍icon=117␍␍[Dictionary]␍path=/kolibrios/utils/dicty.kex␍param=␍icon=79␍␍[FB2Read]␍path=/sys/fb2read␍param=␍icon=44␍␍[Animage]␍path=/sys/media/animage␍param=␍icon=15␍␍[RDSave]␍path=/sys/rdsave␍param=␍icon=17␍␍$=1␍␍[Volume]␍path=/sys/@volume␍param=␍icon=64␍␍[NetStatus]␍path=/sys/network/netstat␍param=␍icon=33␍␍[TaskMan]␍path=/sys/taskman␍param=␍icon=57␍␍[SysPanel]␍path=/sys/syspanel␍param=␍icon=6
+1 -1
View File
@@ -1 +1 @@
[rbmenu]␍Диспетчер процессов=/sys/cpu␍Настройка внешнего вида=/kolibrios/utils/appearance␍;Настройка цветов=/sys/skincfg␍;Сплошной фон=/sys/media/palitra␍[01]␍name=FILES␍path=/sys/File Managers/EOLITE␍param=␍ico=7␍x=4␍y=21␍[02]␍name=FPLAY␍path=/kolibrios/media/fplay␍param=␍ico=96␍x=65␍y=21␍[03]␍name=GAMES␍path=/sys/allgames␍param=␍ico=35␍x=125␍y=21␍[04]␍name=TINYPAD␍path=/sys/tinypad␍param=␍ico=9␍x=4␍y=96␍[05]␍name=zSEA␍path=/kolibrios/media/zsea/zsea␍param=␍ico=46␍x=65␍y=96␍[06]␍name=WEBVIEW␍path=/sys/network/webview␍param=␍ico=31␍x=125␍y=96␍␍; =========␍; RIGHT TOP␍; =========␍␍[10]␍name=DEBUG␍path=/SYS/DEVELOP/MTDBG␍param=␍ico=39␍x=-204␍y=21␍[11]␍name=BOARD␍path=/SYS/DEVELOP/BOARD␍param=␍ico=19␍x=-140␍y=21␍[12]␍name=KPACK␍path=/SYS/KPACK␍param=␍ico=99␍x=-77␍y=21␍[13]␍name=DIFF␍path=/sys/develop/diff␍param=␍ico=84␍x=-203␍y=96␍[14]␍name=FASM␍path=/SYS/DEVELOP/FASM␍param=␍ico=10␍x=-141␍y=96␍[15]␍name=DOCPACK␍path=/sys/network/webview␍param=/kolibrios/res/guide/guide.htm␍ico=8␍x=-76␍y=96␍[16]␍name=SHELL␍path=/SYS/SHELL␍param=␍ico=1␍x=-203␍y=166␍[17]␍name=HEXEDIT␍path=/SYS/DEVELOP/HEED␍param=␍ico=22␍x=-141␍y=166␍[18]␍name=CEDIT␍path=/sys/develop/cedit␍param=␍ico=58␍x=-74␍y=166␍
[rbmenu]␍Диспетчер задач=/sys/taskman␍Настройка внешнего вида=/kolibrios/utils/appearance␍;Настройка цветов=/sys/skincfg␍;Сплошной фон=/sys/media/palitra␍[01]␍name=FILES␍path=/sys/File Managers/EOLITE␍param=␍ico=7␍x=4␍y=21␍[02]␍name=FPLAY␍path=/kolibrios/media/fplay␍param=␍ico=96␍x=65␍y=21␍[03]␍name=GAMES␍path=/sys/allgames␍param=␍ico=35␍x=125␍y=21␍[04]␍name=TINYPAD␍path=/sys/tinypad␍param=␍ico=9␍x=4␍y=96␍[05]␍name=zSEA␍path=/kolibrios/media/zsea/zsea␍param=␍ico=46␍x=65␍y=96␍[06]␍name=WEBVIEW␍path=/sys/network/webview␍param=␍ico=31␍x=125␍y=96␍␍; =========␍; RIGHT TOP␍; =========␍␍[10]␍name=DEBUG␍path=/SYS/DEVELOP/MTDBG␍param=␍ico=39␍x=-204␍y=21␍[11]␍name=BOARD␍path=/SYS/DEVELOP/BOARD␍param=␍ico=19␍x=-140␍y=21␍[12]␍name=KPACK␍path=/SYS/KPACK␍param=␍ico=99␍x=-77␍y=21␍[13]␍name=DIFF␍path=/sys/develop/diff␍param=␍ico=84␍x=-203␍y=96␍[14]␍name=FASM␍path=/SYS/DEVELOP/FASM␍param=␍ico=10␍x=-141␍y=96␍[15]␍name=DOCPACK␍path=/sys/network/webview␍param=/kolibrios/res/guide/guide.htm␍ico=8␍x=-76␍y=96␍[16]␍name=SHELL␍path=/SYS/SHELL␍param=␍ico=1␍x=-203␍y=166␍[17]␍name=HEXEDIT␍path=/SYS/DEVELOP/HEED␍param=␍ico=22␍x=-141␍y=166␍[18]␍name=CEDIT␍path=/sys/develop/cedit␍param=␍ico=58␍x=-74␍y=166␍
+1 -2
View File
@@ -23,8 +23,7 @@ Bus Disconnect=kbd,37
System Settings=setup,5
[Monitoring]
Processes=cpu,60
System Monitor=sysmon,57
Task Manager=taskman,57
Ghost Monitor=gmon,107
Network Status=network/netstat,33
AMDtemp=/k/utils/AMDtemp,128
+1 -1
View File
@@ -1,5 +1,5 @@
[rbmenu]
Processes=cpu
Task manager=taskman
Theme settings=skincfg
Background=/sys/media/palitra
System panel=syspanel
+2 -2
View File
@@ -40,7 +40,7 @@
06 zSea Image Viewer * |/kolibrios/media/zsea/zsea
38 Animage |media/animage
38 IconEdit |media/iconedit
40 Image Filtering |media/imgf/imgf
40 Image Filtering * |/kolibrios/media/ImgF/ImgF
52 Palitra |media/palitra
39 Pipet |develop/pipet
#4 **** MULTIMEDIA
@@ -75,7 +75,7 @@
56 Clipboard viewer |develop/clipview
62 Calendar |calendar
33 Online update * |/kolibrios/utils/osupdate
48 Process manager |cpu
48 Task manager |taskman
24 Terminal |terminal
05 Save ramdisk |rdsave
24 Shell |shell
+1 -1
View File
@@ -1,5 +1,5 @@
[rbmenu]
Processes=cpu
Task manager=taskman
Theme settings=skincfg
Background=/sys/media/palitra
System panel=syspanel
+2 -2
View File
@@ -41,7 +41,7 @@
16 Image viewer KIV |media/kiv
16 Image viewer zSea * |/kolibrios/media/zsea/zsea
16 Animage |media/animage
16 Efectos de imаgenes |media/imgf/imgf
16 Efectos de imаgenes * |/kolibrios/media/ImgF/ImgF
16 Palitra |media/palitra
#4 **** MULTIMEDIA
16 Pixie Audioplayer |media/pixie
@@ -82,7 +82,7 @@
16 Colores y Apariencia |skincfg
16 Atajos de teclado |mykey
#9 **** SENSORES
16 Procesos |cpu
16 Gestor de tareas |taskman
16 Dispositivos PCI |pcidev
16 CPUID |cpuid
16 Ghost Monitor |gmon
+1 -2
View File
@@ -23,8 +23,7 @@ Desconectar bus=kbd,37
Ajustes del sistema=setup,5
[Monitorizacion]
Procesos=cpu,60
Monitor del sistema=sysmon,57
Gestor de tareas=taskman,57
Ghost Monitor=gmon,107
Estado de red=network/netstat,33
AMDtemp=/k/utils/AMDtemp,128
+1 -1
View File
@@ -41,7 +41,7 @@
06 Image viewer zSea * |/kolibrios/media/zsea/zsea
38 Animage |media/animage
38 IconEdit |media/iconedit
16 Image Filtering |media/imgf/imgf
16 Image Filtering * |/kolibrios/media/ImgF/ImgF
52 Palitra |media/palitra
39 Pipet |develop/pipet
#4 **** MULTIMEDIA ****
+1 -1
View File
@@ -41,7 +41,7 @@
06 Image viewer zSea * |/kolibrios/media/zsea/zsea
38 Animage |media/animage
38 IconEdit |media/iconedit
40 Image Filtering |media/imgf/imgf
40 Image Filtering * |/kolibrios/media/ImgF/ImgF
52 Palitra |media/palitra
39 Pipet |develop/pipet
#4 **** MULTIMEDIA
+1 -1
View File
@@ -1,5 +1,5 @@
[rbmenu]
Диспетчер процессов=cpu
Диспетчер задач=taskman
Управление темой=skincfg
Настройка фона=/sys/media/palitra
Системная панель=syspanel
+2 -1
View File
@@ -40,7 +40,7 @@
06 Просмотр фото zSea |/kolibrios/media/zsea/zsea
38 Редактор Animage |media/animage
38 Редактор иконок |media/iconedit
40 Наложение фильтров |media/imgf/imgf
40 Наложение фильтров * |/kolibrios/media/ImgF/ImgF
52 Палитра |media/palitra
39 Пипетка |develop/pipet
#4 **** Звук и видео
@@ -73,6 +73,7 @@
00 Файловые менеджеры > |@8
00 Спец. возможности > |@9
62 Календарь |calendar
48 Диспетчер задач |taskman
51 Виртуальные диски |tmpdisk
24 Терминал |terminal
24 Консоль SHELL |shell
+1 -2
View File
@@ -23,8 +23,7 @@ Hot Angles=HACONFIG,105
Системные настройки=setup,5
[Мониторинг]
Процессы=cpu,60
Системный монитор=sysmon,57
Диспетчер задач=taskman,57
Ghost Monitor=gmon,107
Статус сети=network/netstat,33
AMDtemp=/k/utils/AMDtemp,128
+100 -14
View File
@@ -130,6 +130,8 @@ RU_STATUS_IDLE = 0000b shl 2
RU_STATUS_SUSPENDED = 0001b shl 2
RU_STATUS_NO_RESOURCES = 0010b shl 2
RU_STATUS_READY = 0100b shl 2
SCB_STATUS_CUS = 11000000b ; CU Status
CU_STATUS_ACTIVE = 10b shl 6
SCB_STATUS_FCP = 1 shl 8 ; Flow Control Pause
SCB_STATUS_SWI = 1 shl 10 ; Software Interrupt
SCB_STATUS_MDI = 1 shl 11 ; MDI read/write complete
@@ -183,6 +185,8 @@ struct txfd
ends
TXFD_STATUS_C = 1 shl 15
TXFD_CMD_IA = 1 shl 0
TXFD_CMD_CFG = 1 shl 1
TXFD_CMD_TX = 1 shl 2
@@ -628,6 +632,9 @@ reset:
mov ax, CU_START or INT_MASK
out dx, ax
call cmd_wait
; cmd_wait only means the SCB accepted the command. The Configure below
; reuses confcmd, so a slow chip would read it instead of our MAC.
call confcmd_wait
;-------------
; Configure CU
@@ -652,6 +659,7 @@ reset:
mov ax, CU_START ; expect Interrupts from now on
out dx, ax
call cmd_wait
call confcmd_wait
; Start media check timer
mov [ebx + device.state], ETH_LINK_DOWN
@@ -678,6 +686,11 @@ init_rx_ring:
;---------------------
; build rxfd structure
cmp [ebx + device.rx_desc], 0 ; the RFD of an earlier reset
je @f
invoke NetFree, [ebx + device.rx_desc]
mov [ebx + device.rx_desc], 0
@@:
invoke NetAlloc, 2000
test eax, eax
jz .out_of_mem
@@ -689,6 +702,7 @@ init_rx_ring:
mov [esi + sizeof.NET_BUFF + rxfd.command], RXFD_CMD_EL or RXFD_CMD_SUSPEND
mov [esi + sizeof.NET_BUFF + rxfd.link], eax
mov [esi + sizeof.NET_BUFF + rxfd.count], 0
mov [esi + sizeof.NET_BUFF + rxfd.rx_buf_addr], 0xffffffff ; simplified mode, no RBD
mov [esi + sizeof.NET_BUFF + rxfd.size], 1528
ret
@@ -709,6 +723,15 @@ init_tx_ring:
invoke GetPhysAddr
mov ecx, TX_RING_SIZE
.next_desc:
; after a reset with frames still unreclaimed: free them, or transmit sees the
; descriptor busy (virt_addr) and reports TX overrun forever
cmp [esi + txfd.virt_addr], 0
je @f
push eax ecx
invoke NetFree, [esi + txfd.virt_addr]
pop ecx eax
mov [esi + txfd.virt_addr], 0
@@:
mov [esi + txfd.status], 0
mov [esi + txfd.command], 0
lea edx, [eax + txfd.buf_addr]
@@ -763,7 +786,7 @@ proc transmit stdcall bufferptr
lea edi, [ebx + device.tx_ring + eax]
; Check if current descriptor is free or still in use
cmp [edi + txfd.status], 0
cmp [edi + txfd.virt_addr], 0 ; buffer not reclaimed yet
jne .overrun
; Fill in status and command values
@@ -786,6 +809,22 @@ proc transmit stdcall bufferptr
mov eax, edi
invoke GetPhysAddr
set_io [ebx + device.io_addr], 0
; CU_START is only valid while the CU is idle or suspended:
; wait for the previous frame to leave (1.2 ms at 10 Mbit)
push eax ecx
set_io [ebx + device.io_addr], REG_SCB_STATUS
mov ecx, 100000
.cu_busy:
in al, dx
and al, SCB_STATUS_CUS
cmp al, CU_STATUS_ACTIVE
jne .cu_free
dec ecx
jnz .cu_busy
DEBUGF 2, "CU still active, starting anyway\n"
.cu_free:
pop ecx eax
set_io [ebx + device.io_addr], REG_SCB_PTR
out dx, eax
@@ -854,7 +893,7 @@ int_handler:
DEBUGF 1,"Status: %x\n", ax
test ax, SCB_STATUS_FR ; did we receive a frame?
test ax, SCB_STATUS_FR or SCB_STATUS_RNR ; frame received or receiver stopped?
jz .no_rx
push ax
@@ -901,6 +940,7 @@ int_handler:
mov [esi + sizeof.NET_BUFF + rxfd.command], RXFD_CMD_EL or RXFD_CMD_SUSPEND
mov [esi + sizeof.NET_BUFF + rxfd.link], eax
mov [esi + sizeof.NET_BUFF + rxfd.count], 0
mov [esi + sizeof.NET_BUFF + rxfd.rx_buf_addr], 0xffffffff ; simplified mode, no RBD
mov [esi + sizeof.NET_BUFF + rxfd.size], 1528
; restart RX
@@ -916,11 +956,22 @@ int_handler:
mov ax, RX_START
out dx, ax
call cmd_wait
.out_of_mem:
; Hand the frame over to the kernel
jmp [EthInput]
.out_of_mem:
; The buffer is still our only RFD: drop the frame and reuse it
mov esi, [esp] ; the buffer
mov ecx, [esi + NET_BUFF.length]
dec [ebx + device.packets_rx] ; counted above, before the allocation
sub dword [ebx + device.bytes_rx], ecx
sbb dword [ebx + device.bytes_rx + 4], 0
inc [ebx + device.packets_rx_drop]
add esp, 12 ; buffer, .rx_loop, ebx
mov esi, [ebx + device.rx_desc]
jmp .not_ok
.not_ok:
; Reset the FD
mov [esi + sizeof.NET_BUFF + rxfd.status], 0
@@ -945,6 +996,27 @@ int_handler:
.no_rx_:
DEBUGF 1, "no more data\n"
; With a single RFD the receiver sits in No Resources/Suspended whenever a
; frame arrived before we re-armed it. Nothing restarts it but us.
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], REG_SCB_STATUS
in al, dx
and al, SCB_STATUS_RUS
cmp al, RU_STATUS_READY
je .ru_ready
test byte[esp], 1 ; bit 0 of the saved status is reserved,
jnz .ru_ready ; we mark it: one restart per IRQ
or byte[esp], 1
movzx eax, al
DEBUGF 1, "Restarting receiver, RU status %x\n", eax:2
mov esi, [ebx + device.rx_desc]
push ebx
test [esi + sizeof.NET_BUFF + rxfd.status], RXFD_STATUS_C
jnz .rx_loop ; a frame completed meanwhile
add esp, 4
jmp .not_ok ; re-arm the empty RFD
.ru_ready:
pop ax
.no_rx:
@@ -955,13 +1027,13 @@ int_handler:
push eax
.loop_tx:
mov edi, [ebx + device.last_tx]
mov eax, sizeof.txfd
mul eax
mov eax, [ebx + device.last_tx]
mov edx, sizeof.txfd
mul edx
lea edi, [ebx + device.tx_ring + eax]
cmp [edi + txfd.status], 0
je .tx_done
test [edi + txfd.status], TXFD_STATUS_C ; sent by the device?
jz .tx_done
cmp [edi + txfd.virt_addr], 0
je .tx_done
@@ -970,6 +1042,7 @@ int_handler:
push [edi + txfd.virt_addr]
mov [edi + txfd.virt_addr], 0
mov [edi + txfd.status], 0 ; free for transmit again
invoke NetFree
inc [ebx + device.last_tx]
@@ -980,12 +1053,6 @@ int_handler:
pop eax
.no_tx:
test ax, RU_STATUS_NO_RESOURCES
jz .not_out_of_resources
DEBUGF 2, "Out of resources!\n"
.not_out_of_resources:
pop edi esi ebx
xor eax, eax
inc eax
@@ -1079,6 +1146,25 @@ proc check_media_mii stdcall dev:dword
endp
; Wait (up to 1 s) until the device has executed the command in confcmd.
align 4
confcmd_wait:
mov ecx, 1000 ; udelay = Sleep(1), 1 ms
.loop:
test [ebx + device.confcmd.status], TXFD_STATUS_C
jnz .done
call udelay
dec ecx
jnz .loop
movzx eax, [ebx + device.confcmd.command]
DEBUGF 2, "Command 0x%x not completed\n", eax:4
ret
.done:
movzx eax, [ebx + device.confcmd.command]
movzx ecx, [ebx + device.confcmd.status]
DEBUGF 1, "Command 0x%x done, status 0x%x\n", eax:4, ecx:4
ret
align 4
cmd_wait:
+91 -3
View File
@@ -72,9 +72,26 @@ I2CHID_PWR_ON = 0x00
; single tick forever.
MAX_POLL_ERRORS = 100
; Polls of silence before the next recovery step is tried (20 ms each).
; Polls of silence before the next recovery step is tried (10 ms each).
; The ladder exists for bringing up a pad that never reports at all, and is
; compiled in only at debug level 1: on a working pad it would run merely
; because nobody touched it during the first seconds after boot, and the
; power cycle, the second reset and the poll-mode flips it consists of are
; exactly the kind of thing a fragile firmware answers with silence.
SILENT_LIMIT = 150
; A pad that has ever answered an idle poll with an empty length, yet keeps
; returning one and the same non-empty frame, has stopped producing frames:
; a finger on the surface changes the scan time in every report, and a pad
; that holds its last frame instead of answering empty (Elan) never counts
; here. Seen on the SIPODEV SP1064: a single frame came through and was
; then repeated on every poll for good. This many identical answers in a
; row, and the device is reset and switched into touchpad mode again; the
; limit doubles on each reset, up to the maximum, so a pad that stays wedged
; is retried, not hammered.
STUCK_DUPS = 100
STUCK_DUPS_MAX = 3000
; ---------------------------- Settings -------------------------------------
; Everything below has a built-in default and can be overridden from the
; [touchpad] section of /sys/settings/system.ini. The file is read once at
@@ -1686,6 +1703,56 @@ proc set_ptp_mode uses ebx esi edi
ret
endp
; The pad has wedged (see STUCK_DUPS): drop whatever touch the driver holds,
; then bring the device up again the way setup_device did - RESET, a quiet
; wait, one read to consume the ack, SET_POWER(ON), and the touchpad mode,
; which the reset cleared. Runs in the poll thread.
proc reinit_device uses ebx esi edi
inc [StReinit]
DEBUGF 2, "i2chid: pad stuck: the same frame %u polls in a row, resetting it (%u so far)\n", [DupRun], [StReinit]
mov [DupRun], 0
mov eax, [StuckLimit]
add eax, eax
cmp eax, STUCK_DUPS_MAX
jbe @f
mov eax, STUCK_DUPS_MAX
@@:
mov [StuckLimit], eax
; Whatever the driver was in the middle of is over: no finger, no button.
call ptp_forget
mov [PrevTip], 0
mov [BtnLatch], 0
mov [HeldBtn], 0
mov [TapHold], 0
mov [TapRelease], 0
mov [PendingPress], 0
mov [DragActive], 0
invoke SetMouseData, 0, 0, 0, 0, 0
stdcall hid_command, 0, I2CHID_OP_RESET
test eax, eax
jz @f
DEBUGF 2, "i2chid: RESET failed (%x)\n", eax
@@:
mov esi, 150
invoke Sleep
stdcall dw_read_block, [SlaveAddr], 0, 0, input_buf, [MaxInput]
stdcall hid_command, I2CHID_PWR_ON, I2CHID_OP_SET_POWER
test eax, eax
jz @f
DEBUGF 2, "i2chid: post-reset SET_POWER failed (%x)\n", eax
@@:
mov esi, 10
invoke Sleep
call set_ptp_mode
mov [PollMode], 0
; The held frame is stale now; the next one the pad sends must count as new.
mov edi, prev_rep
mov ecx, MAX_INPUT_BUF
xor eax, eax
rep stosb
ret
endp
; Asks the device for every report it declared, as both an Input and a
; Feature report, and logs each answer. A pad whose sensor is alive but
; whose reporting mode was never selected will answer at least one of
@@ -1883,8 +1950,8 @@ proc i2chid_thread
test edx, edx
jnz @f
.stats:
DEBUGF 2, "i2chid: after %u polls: %u reads, %u reports, %u duplicates, %u empty, at most %u per poll, %u lifts by silence\n", \
[StPolls], [StReads], [StReports], [StDups], [StEmpty], [StMaxDrain], [StForced]
DEBUGF 2, "i2chid: after %u polls: %u reads, %u reports, %u duplicates, %u empty, at most %u per poll, %u lifts by silence, %u resets\n", \
[StPolls], [StReads], [StReports], [StDups], [StEmpty], [StMaxDrain], [StForced], [StReinit]
@@:
; Syscall 5 is the delay that sleeps on an event and yields; the Sleep import
; drivers normally use is delay_ms, which busy-waits and would burn a core.
@@ -1965,6 +2032,8 @@ proc i2chid_poll_once uses ebx esi edi
mov [GotAny], 1
mov [Consumed], 1
inc [StReports]
mov [DupRun], 0
mov [StuckLimit], STUCK_DUPS
; The first few reports are dumped raw, before any interpretation, so that a
; touchpad which does send data but whose bytes the driver reads wrongly can
; be told apart from one that says nothing at all.
@@ -2068,9 +2137,17 @@ proc i2chid_poll_once uses ebx esi edi
.duplicate:
pop eax
inc [StDups]
cmp [StEmpty], 0
je .done ; holding the last frame is this pad's idle
inc [DupRun]
mov eax, [DupRun]
cmp eax, [StuckLimit]
jb .done
call reinit_device
jmp .done
.silent:
inc [StEmpty]
mov [DupRun], 0
; Nothing arrived. An idle answer is still evidence: if the device reacts
; to a finger at all, something in those bytes changes even when it never
; sets a length, so the first answers and every change are logged.
@@ -2080,6 +2157,8 @@ proc i2chid_poll_once uses ebx esi edi
; If any of them wakes the device, GotAny freezes the ladder for good.
cmp [GotAny], 0
jnz .done
cmp [LadderOn], 0
jz .done
inc [SilentPolls]
cmp [SilentPolls], SILENT_LIMIT
jb .done
@@ -2759,6 +2838,15 @@ TraceCount dd 8
DecodeTrace dd 8
GotAny dd 0
SilentPolls dd 0
DupRun dd 0
; The bring-up ladder runs only in a level-1 (chatty) build.
if __DEBUG_LEVEL__ > 1
LadderOn dd 0
else
LadderOn dd 1
end if
StuckLimit dd STUCK_DUPS
StReinit dd 0
; Parser state (see hidmin.inc).
p_usage_page dd 0
File diff suppressed because it is too large. Load diff
+1 -2
View File
@@ -842,8 +842,7 @@ disk_scan_partitions:
cmp ebx, mbr_buffer
jz .release_partition_buffer
; 15b. If we have allocated it, free it.
xchg eax, ebx
call free
stdcall kernel_free, ebx
jmp .nothing
; 15c. Otherwise, release reference.
.release_partition_buffer:
+1
View File
@@ -4148,6 +4148,7 @@ Structure of block of data for folder entry (BDFE):
and after archiving this bit is cleared - it can be useful
for automatically creating of backup-archives as at writing
this bit is usually set
* bit 6 (mask 0x40): this is a symbolic link (currently only set by the ext driver).
* +4: dword: encoding, equals to field +8 in the information structure
* +8: 4*byte: time of file creation
* +12 = +0xC: 4*byte: date of file creation
+6
View File
@@ -212,6 +212,7 @@ DIR_DIRECTORY = 2
DIR_SYMLINK = 7
KOS_HIDDEN = 2
KOS_DIRECTORY = 10h
KOS_SYMLINK = 40h
READ_ONLY = 1
SYMLINK_MAX_DEPTH = 40
FAST_SYMLINK_MAX_SIZE = 60
@@ -3392,6 +3393,11 @@ ext_ReadFolder:
stosd
mov eax, [esi+INODE.fileSizeHigh]
stosd
movzx eax, [esi+INODE.accessMode]
and eax, TYPE_MASK
cmp eax, FLAG_SYMLINK
jne @f
or dword [edx], KOS_SYMLINK
@@:
mov esi, [esp+12]
movzx ecx, [esi+DIRENTRY.nameLength]
+1 -1
View File
@@ -2628,7 +2628,7 @@ modify_pce:
iglobal
cpustring db 'CPU',0
cpustring db 'TASKMAN',0
endg
uglobal
+28
View File
@@ -83,6 +83,31 @@ macro arp_init {
}
;-----------------------------------------------------------------;
; ;
; arp_clear_device: Empty the ARP table and counters of a removed ;
; device. ;
; ;
; IN: edi = device number * 4 ;
; ;
;-----------------------------------------------------------------;
macro arp_clear_device {
xor eax, eax
mov [ARP_entries + edi], eax
mov [ARP_packets_tx + edi], eax
mov [ARP_packets_rx + edi], eax
mov [ARP_conflicts + edi], eax
push edi
imul edi, (ARP_TABLE_SIZE * sizeof.ARP_entry)/4
add edi, ARP_table
mov ecx, (ARP_TABLE_SIZE * sizeof.ARP_entry)/2
rep stosw
pop edi
}
;-----------------------------------------------------------------;
; ;
; arp_decrease_entry_ttls ;
@@ -313,6 +338,9 @@ arp_output_request:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_output_request: ip=%u.%u.%u.%u device=0x%x\n",\
[esp]:1, [esp + 1]:1, [esp + 2]:1, [esp + 3]:1, ebx
test ebx, ebx ; device is gone
jz .exit
mov ax, ETHER_PROTO_ARP
mov ecx, sizeof.ARP_header
mov edx, ETH_BROADCAST ; broadcast mac
+40 -1
View File
@@ -105,6 +105,29 @@ macro ipv4_init {
}
;-----------------------------------------------------------------;
; ;
; ipv4_clear_device: Reset the IPv4 settings of a removed device, ;
; so no route points to it anymore. ;
; ;
; IN: edi = device number * 4 ;
; ;
;-----------------------------------------------------------------;
macro ipv4_clear_device {
xor eax, eax
mov [IPv4_address + edi], eax
mov [IPv4_subnet + edi], eax
mov [IPv4_nameserver + edi], eax
mov [IPv4_gateway + edi], eax
mov [IPv4_broadcast + edi], eax
mov [IPv4_packets_tx + edi], eax
mov [IPv4_packets_rx + edi], eax
mov [IPv4_packets_dumped + edi], eax
}
;-----------------------------------------------------------------;
; ;
; Decrease TimeToLive of all fragment slots ;
@@ -757,6 +780,8 @@ ipv4_output_raw:
push esi eax
call ipv4_route
test eax, eax
jz .arp_error
call arp_ip_to_mac
test eax, 0xffff0000 ; error bits
@@ -967,6 +992,8 @@ ipv4_route:
; Check for on-link
xor edi, edi
.loop:
cmp [net_device_list + edi], 0 ; skip slots without a device
je .next
mov ebx, [IPv4_address + edi]
and ebx, [IPv4_subnet + edi]
jz .next
@@ -983,7 +1010,10 @@ ipv4_route:
mov edi, 4 ; skip loopback device
.loop_gw:
cmp [IPv4_gateway + edi], 0
je .next_gw
cmp [net_device_list + edi], 0
jne .found_gw
.next_gw:
add edi, 4
cmp edi, 4*NET_DEVICES_MAX
jb .loop_gw
@@ -1049,14 +1079,23 @@ ipv4_route:
cmp eax, 0xffffffff
je @f
; An interface without an address (DHCP not done yet, or the lease
; dropped when the link went down) can send nothing but broadcasts: with
; address and mask both zero every destination compared as on-link, and
; the stack went asking ARP for internet addresses on behalf of 0.0.0.0.
test edx, edx
jz .fail
; Check if we should route to gateway or not
mov ebx, [IPv4_address + edi]
mov ebx, edx
and ebx, [IPv4_subnet + edi]
mov ecx, eax
and ecx, [IPv4_subnet + edi]
cmp ecx, ebx
je @f
mov eax, [IPv4_gateway + edi]
test eax, eax
jz .fail ; off-link and no gateway
@@:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
ret
+44 -1
View File
@@ -61,6 +61,41 @@ macro eth_init {
}
;-----------------------------------------------------------------;
; ;
; eth_clear_device: Drop the frames of a removed device that are ;
; still waiting in the input queue, their ;
; NET_BUFF.device will not be valid anymore. ;
; ;
; IN: ebx = device ptr ;
; ;
;-----------------------------------------------------------------;
macro eth_clear_device {
local .loop, .done
spin_lock_irqsave
mov esi, [ETH_frame_head]
.loop:
cmp esi, ETH_frame_head
je .done
mov eax, esi
mov esi, [esi + NET_BUFF.NextPtr]
cmp [eax + NET_BUFF.device], ebx
jne .loop
; unlink it, ETH_frame_head/tail double as the NextPtr/PrevPtr of the list head
mov ecx, [eax + NET_BUFF.PrevPtr]
mov [ecx + NET_BUFF.NextPtr], esi
mov [esi + NET_BUFF.PrevPtr], ecx
dec [ETH_frame_queued]
stdcall net_buff_free, eax
jmp .loop
.done:
spin_unlock_irqrestore
}
align 4
; This function is called by ethernet drivers.
; Push the received ethernet packet onto the ethernet input queue.
@@ -245,6 +280,9 @@ eth_output:
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_output: size=%u device=%x\n", ecx, ebx
test ebx, ebx
jz .no_device
cmp ecx, [ebx + ETH_DEVICE.mtu]
ja .too_large
@@ -295,11 +333,16 @@ eth_output:
ret
.too_large:
inc [eax + NET_DEVICE.packets_tx_err]
inc [ebx + NET_DEVICE.packets_tx_err]
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_output: Packet too large!\n"
xor eax, eax
ret
.no_device:
DEBUGF DEBUG_NETWORK_ERROR, "ETH_output: no device!\n"
xor eax, eax
ret
;-----------------------------------------------------------------;
+10
View File
@@ -597,6 +597,16 @@ net_remove_device:
mov dword [edi-4], eax
dec [net_device_count]
;-----------------------------------------------------------------
; Forget everything the protocols still know about this interface.
; Otherwise its IP address keeps matching in ipv4_route, and output
; ends up calling through the now empty net_device_list slot.
sub edi, net_device_list + 4 ; device number * 4
ipv4_clear_device
arp_clear_device
eth_clear_device
call net_send_event
xor eax, eax
+6 -2
View File
@@ -1422,10 +1422,14 @@ endl
test [edx + TCP_header.Flags], TH_ACK
jz .drop
mov eax, ebx
push ebx
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
pop eax
mov ebx, ECONNREFUSED
call tcp_drop
jmp .drop
jmp .drop_no_socket
@@:
;-----------------------------------------------------------------------------------
+8 -6
View File
@@ -234,23 +234,25 @@ endl
mov ebx, TCP_max_win
shl ebx, cl
pop ecx
sub ebx, [eax + TCP_SOCKET.RCV_ADV]
add ebx, [eax + TCP_SOCKET.RCV_NXT]
; Clamp to available window first, then subtract what the peer already knows (as in BSD)
cmp ebx, ecx
jl @f
jbe @f
mov ebx, ecx
@@:
sub ebx, [eax + TCP_SOCKET.RCV_ADV]
add ebx, [eax + TCP_SOCKET.RCV_NXT]
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: we can increase window by %d bytes\n", ebx
mov edi, [eax + TCP_SOCKET.t_maxseg]
shl edi, 1
cmp ebx, edi
jae .send
cmp ebx, edi ; signed: may be negative if window shrank
jge .send
cmp ebx, SOCKET_BUFFER_SIZE/2
jae .send
jge .send
.no_window:
+4
View File
@@ -180,6 +180,8 @@ tcp_connect:
.nomem:
pop edx eax
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
xor eax, eax
dec eax
mov ebx, ENOMEM
@@ -194,6 +196,8 @@ tcp_connect:
.enoroute:
pop eax
popa
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
xor eax, eax
dec eax
mov ebx, EADDRNOTAVAIL
-4
View File
@@ -238,7 +238,6 @@ BEGIN
m.active := FALSE;
resetTimer;
m.tid := 0;
G.destroy(m.canvas);
K.Exit
END exit;
@@ -250,7 +249,6 @@ BEGIN
resetTimer
END;
m.tid := 0;
G.destroy(m.canvas);
K.Exit
END escape;
@@ -356,7 +354,6 @@ BEGIN
END;
temp := m.tid;
m.tid := 0;
G.destroy(m.canvas);
K.ExitID(temp);
m.active := FALSE
END
@@ -512,7 +509,6 @@ BEGIN
IF m.parent # NIL THEN
temp := m.parent.tid;
m.parent.tid := 0;
G.destroy(m.parent.canvas);
K.ExitID(temp)
END;
exit(m)
@@ -1,6 +1,6 @@
#include <shell_api.h>
char shell_getc()
int shell_getc()
{
__shell_init();
@@ -9,7 +9,7 @@ char shell_getc()
__shell_shm->cmd = SHELL_GETC;
__SHELL_WAIT();
return __shell_shm->data[0];
return *((int*)__shell_shm->data);
}
else
{
@@ -1,15 +1,28 @@
#include <shell_api.h>
#include <stdio.h>
#include <string.h>
void shell_gets(char *str, int n)
char *shell_gets(char *str, int n)
{
__shell_init();
char *ptr = NULL;
if (__shell_is_init == __SHELL_INIT_OK)
{
__shell_shm->cmd = SHELL_GETS;
__SHELL_WAIT();
strncpy(str, __shell_shm->data, n);
if (__shell_shm->return_value.str == EOF || !__shell_shm->return_value.str)
{
ptr = __shell_shm->return_value.str;
}
else
{
ptr = str;
}
}
return ptr;
}
@@ -1,12 +1,13 @@
#include <shell_api.h>
#include <stdio.h>
void shell_printf(const char *format, ...)
int shell_printf(const char *format, ...)
{
va_list ap;
va_start(ap, format);
vsnprintf(__shell_shm->data, sizeof(__shell_shm->data), format, ap);
int val = vsnprintf(__shell_shm->data, sizeof(__shell_shm->data), format, ap);
__shell_shm->cmd = SHELL_PUTS;
va_end(ap);
__SHELL_WAIT();
return val;
}
@@ -1,7 +1,7 @@
#include <shell_api.h>
#include <string.h>
void shell_puts(const char *str)
size_t shell_puts(const char *str)
{
shell_write_string(str, strlen(str));
return shell_write_string(str, strlen(str));
}
@@ -1,22 +1,27 @@
#include <shell_api.h>
#include <string.h>
void shell_write_string(const char *s, size_t len)
size_t shell_write_string(const char *s, size_t len)
{
__shell_init();
if (__shell_is_init == __SHELL_INIT_OK)
{
size_t written_bytes = 0;
if (len > sizeof(__shell_shm->data) - 1)
{
shell_write_string(s, sizeof(__shell_shm->data) - 1); // Outputs as much as it can.
shell_write_string(s + (sizeof(__shell_shm->data) - 1), len - (sizeof(__shell_shm->data) - 1)); // Outputs the rest.
written_bytes += shell_write_string(s, sizeof(__shell_shm->data) - 1); // Outputs as much as it can.
written_bytes += shell_write_string(s + (sizeof(__shell_shm->data) - 1), len - (sizeof(__shell_shm->data) - 1)); // Outputs the rest.
}
else
{
memset(__shell_shm->data, 0, sizeof(__shell_shm->data)); // without int shell show \t, \n, lose chars and other trash
memcpy(__shell_shm->data, s, len);
memset(__shell_shm->data, 0, sizeof(__shell_shm->data)); // without int shell show \t, \n, lose chars and other trash
memcpy(__shell_shm->data, s, len);
__shell_shm->cmd = SHELL_PUTS;
__SHELL_WAIT();
written_bytes += __shell_shm->return_value.written_bytes;
}
return written_bytes;
}
return 0;
}
@@ -31,9 +31,15 @@ enum __SHELL_INIT_STATE {
};
#pragma pack(push, 1)
struct return_value {
size_t written_bytes;
char* str;
};
struct shell_shm_buffer {
uint8_t cmd;
char data[SHELL_SHM_MAX - sizeof(((struct shell_shm_buffer*)NULL)->cmd)];
char data[SHELL_SHM_MAX - sizeof(((struct shell_shm_buffer*)NULL)->cmd) - sizeof(struct return_value)];
struct return_value return_value;
};
#pragma pack(pop)
@@ -51,14 +57,14 @@ __EXTERN int shell_ping();
__EXTERN unsigned shell_get_pid();
__EXTERN void shell_exit();
__EXTERN char shell_getc();
__EXTERN void shell_gets(char* str, int n);
__EXTERN int shell_getc();
__EXTERN char* shell_gets(char* str, int n);
__EXTERN void shell_putc(char c);
__EXTERN void shell_puts(const char* str);
__EXTERN void shell_printf(const char* format, ...);
__EXTERN size_t shell_puts(const char* str);
__EXTERN int shell_printf(const char* format, ...);
__EXTERN void shell_write_string(const char* s, size_t len);
__EXTERN size_t shell_write_string(const char* s, size_t len);
__EXTERN void shell_cls();
+15 -5
View File
@@ -34,6 +34,8 @@
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
DLLAPI int puts(const char* str);
DLLAPI int printf(const char* format, ...);
@@ -50,15 +52,23 @@ typedef size_t fpos_t;
#define _FILEMODE_R 1 << 0 // Read
#define _FILEMODE_W 1 << 1 // Write
#define _FILEMODE_A 1 << 2 // Append
#define _FILEMODE_PLUS 1 << 3 // Plus
#define _FILEFLAG_ERR 1 << 3 // Error
#define _FILEFLAG_EOF 1 << 4 // EOF
typedef struct FILE_s {
char* name;
fpos_t position;
int error;
int eof;
int mode; // flags _FILEMODE_*
int __ungetc_emu_buff; // Uses __ungetc_emu (temporary solution!)
union {
struct {
bool read : 1;
bool write : 1;
bool append : 1;
bool error : 1;
bool eof : 1;
};
uint32_t val; // exist just because tcc won't optimize bitfields
} flags;
} FILE;
#define _IOFBF 0
@@ -82,7 +92,7 @@ typedef struct FILE_s {
#define TMP_MAX FOPEN_MAX
#define stderr (FILE*)3
#define stdin (FILE*)1
#define stdin (FILE*)1
#define stdout (FILE*)2
DLLAPI int fgetc(FILE*);
@@ -61,6 +61,8 @@
/* strntold() is used by vsscanf() below; include its definition first */
#include "stdlib/strntold.c"
#include "stdio/vsscanf.c"
#include "stdio/fclose_r.c"
#include "stdio/fopen_r.c"
#include "string/memccpy.c"
#include "string/memchr.c"
@@ -0,0 +1,9 @@
#ifndef __LIBC_STDIO_H
#define __LIBC_STDIO_H
#include <stdio.h>
int fclose_r(FILE* stream);
FILE* fopen_r(const char* restrict name, const char* restrict mode, FILE* restrict stream);
#endif // __LIBC_STDIO_H
@@ -1,6 +1,6 @@
#include <stdio.h>
void clearerr(FILE *stream) {
stream->error = 0;
stream->eof = 0;
void clearerr(FILE* stream)
{
stream->flags.val &= ~(_FILEFLAG_ERR | _FILEFLAG_EOF);
}
@@ -1,8 +1,15 @@
#include "stddef.h"
#include "_stdio.h"
#include <stdio.h>
#include <stdlib.h>
int fclose(FILE *stream) {
int fclose(FILE* stream)
{
int err = fclose_r(stream);
if (err) {
return err;
}
free(stream);
stream = NULL;
return 0;
@@ -0,0 +1,10 @@
#include "_stdio.h"
int fclose_r(FILE* stream)
{
if (stream->name) {
free(stream->name);
}
return 0;
}
@@ -1,5 +1,6 @@
#include <stdio.h>
int feof(FILE *stream) {
return stream->eof;
int feof(FILE* stream)
{
return stream->flags.eof;
}
@@ -1,5 +1,6 @@
#include <stdio.h>
int ferror(FILE *stream) {
return stream->error;
int ferror(FILE* stream)
{
return stream->flags.error;
}
@@ -1,7 +1,22 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "_stdio.h"
FILE *fopen(const char *restrict _name, const char *restrict _mode) {
FILE *out = malloc(sizeof(FILE));
return freopen(_name, _mode, out);
FILE* fopen(const char* restrict _name, const char* restrict _mode)
{
FILE* stream = malloc(sizeof(FILE));
if (stream == NULL) {
errno = ENOMEM;
return NULL;
}
FILE* out = fopen_r(_name, _mode, stream);
if (out == NULL) {
free(stream);
}
return out;
}
@@ -0,0 +1,81 @@
#include "_stdio.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ksys.h>
#include <sys/dirent.h>
/*
Open new file
*/
FILE* fopen_r(const char* restrict _name, const char* restrict _mode, FILE* restrict out)
{
if (!_name || !_mode || !out) {
errno = EINVAL;
return NULL;
}
bool file_not_exits = false;
ksys_bdfe_t info;
{
int err = _ksys_file_get_info(_name, &info);
switch (err) {
case KSYS_FS_ERR_SUCCESS:
if (info.attributes & IS_FOLDER) {
errno = EISDIR;
return NULL;
}
break;
case KSYS_FS_ERR_5:
file_not_exits = true;
break;
default:
errno = err;
return NULL;
break;
}
}
out->flags.val = 0;
out->position = 0;
out->name = strdup(_name);
if (strchr(_mode, 'r')) {
out->flags.read = true;
if (file_not_exits) {
errno = ENOENT;
free(out->name);
return NULL;
}
}
if (strchr(_mode, 'w')) {
out->flags.write = true;
}
if (strchr(_mode, 'a')) {
out->flags.val |= _FILEMODE_W | _FILEMODE_A;
}
if (strchr(_mode, '+')) {
out->flags.val |= _FILEMODE_R | _FILEMODE_W;
}
if (out->flags.write) {
if (file_not_exits) {
int err = _ksys_file_create(_name);
if (err != KSYS_FS_ERR_SUCCESS) {
errno = err;
free(out->name);
return NULL;
}
}
}
if (out->flags.append) {
out->position = info.size;
}
return out;
}
@@ -14,7 +14,7 @@ size_t fread(void *restrict ptr, size_t size, size_t nmemb, FILE *restrict strea
if(size<=0 || nmemb<=0){
errno = EINVAL;
stream->error=errno;
stream->flags.error = true;
return 0;
}
@@ -23,7 +23,7 @@ size_t fread(void *restrict ptr, size_t size, size_t nmemb, FILE *restrict strea
return nmemb;
}
if(stream->mode != _FILEMODE_W && stream->mode != _FILEMODE_A){
if(stream->flags.read){
if(!stream->__ungetc_emu_buff){
((char*) ptr)[0]=(char)stream->__ungetc_emu_buff;
//debug_printf("Ungetc: %x\n", ((char*) ptr)[0]);
@@ -31,10 +31,10 @@ size_t fread(void *restrict ptr, size_t size, size_t nmemb, FILE *restrict strea
unsigned status = _ksys_file_read_file(stream->name, stream->position, bytes_count, ptr , &bytes_read);
if (status != KSYS_FS_ERR_SUCCESS) {
if(status == KSYS_FS_ERR_EOF){
stream->eof=1;
stream->flags.eof = true;
}else{
errno = EIO;
stream->error = errno;
stream->flags.error = true;
return 0;
}
}
@@ -1,62 +1,14 @@
#include <stddef.h>
#include <sys/ksys.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/dirent.h>
#include "_stdio.h"
FILE* freopen(const char* restrict _name, const char* restrict _mode, FILE* restrict out)
{
fclose_r(out);
static FILE* _set_errno(FILE *out, int err){
errno = err;
if(out){
free(out->name);
free(out);
if (_name == NULL) {
_name = out->name;
}
out = NULL;
return out;
return fopen_r(_name, _mode, out);
}
static void _create_file(char *name, FILE *out){
if(_ksys_file_create(name)){
_set_errno(out, EIO);
}
}
FILE *freopen(const char *restrict _name, const char *restrict _mode, FILE *restrict out) {
if(!_name || !_mode || !out){
return _set_errno(out, EINVAL);
}
ksys_bdfe_t info;
int no_file = _ksys_file_get_info(_name, &info);
if(!no_file && info.attributes & IS_FOLDER){
return _set_errno(out, EISDIR);
}
out->eof=0;
out->error=0;
out->position=0;
out->name = strdup(_name);
if (strchr(_mode, 'r')) { out->mode = _FILEMODE_R; }
if (strchr(_mode, 'w')) { out->mode = _FILEMODE_W; }
if (strchr(_mode, 'a')) { out->mode = _FILEMODE_A; }
if (strchr(_mode, '+')) { out->mode |= _FILEMODE_PLUS; }
if(out->mode & _FILEMODE_A){
if(no_file){
_create_file(out->name, out);
}
out->position = info.size;
}else if(out->mode & _FILEMODE_W){
_create_file(out->name, out);
}else if((out->mode & _FILEMODE_R)){
if(no_file){
_set_errno(out, ENOENT);
}
}else{
_set_errno(out, EINVAL);
}
return out;
}
@@ -1,18 +1,19 @@
#include <stdio.h>
#include <sys/ksys.h>
int fseek(FILE *stream, long int offset, int whence) {
if (whence == SEEK_SET) {
stream->position = offset;
} else if (whence == SEEK_CUR) {
stream->position += offset;
} else if (whence == SEEK_END) {
ksys_bdfe_t info;
if (_ksys_file_get_info(stream->name, &info)) {
return -1;
}
stream->position = info.size + offset;
}
stream->eof = 0;
int fseek(FILE* stream, long int offset, int whence)
{
if (whence == SEEK_SET) {
stream->position = offset;
} else if (whence == SEEK_CUR) {
stream->position += offset;
} else if (whence == SEEK_END) {
ksys_bdfe_t info;
if (_ksys_file_get_info(stream->name, &info)) {
return -1;
}
stream->position = info.size + offset;
}
stream->flags.eof = false;
return 0;
}
@@ -1,7 +1,8 @@
#include <stdio.h>
int fsetpos(FILE *stream, const fpos_t *pos) {
int fsetpos(FILE* stream, const fpos_t* pos)
{
stream->position = *pos;
stream->eof = 0;
stream->flags.eof = false;
return 0;
}
@@ -16,7 +16,7 @@ size_t fwrite(const void* restrict ptr, size_t size, size_t nmemb, FILE* restric
if (size <= 0 || nmemb <= 0) {
errno = EINVAL;
stream->error = errno;
stream->flags.error = true;
return 0;
}
@@ -33,11 +33,11 @@ size_t fwrite(const void* restrict ptr, size_t size, size_t nmemb, FILE* restric
return nmemb;
}
if (stream->mode != _FILEMODE_R) {
if (stream->flags.write) {
unsigned status = _ksys_file_write_file(stream->name, stream->position, bytes_count, ptr, &bytes_written);
if (status != KSYS_FS_ERR_SUCCESS) {
errno = EIO;
stream->error = errno;
stream->flags.error = true;
return 0;
}
stream->position += bytes_written;
@@ -6,22 +6,21 @@ int ungetc(int c, FILE* file)
{
int res;
if(!file){
errno = EBADF;
return EOF;
}
if (file->mode != _FILEMODE_R){
errno = EACCES;
return EOF;
}
if (file->position == 0 || c == EOF)
{
errno = EOF;
if (!file) {
errno = EBADF;
return EOF;
}
if (!file->flags.read) {
errno = EACCES;
return EOF;
}
if (file->position == 0 || c == EOF) {
errno = EOF;
return EOF;
}
file->__ungetc_emu_buff = c;
file->position--;
return c;
+5 -3
View File
@@ -1618,21 +1618,23 @@ endl
; Open a new TCP socket
mcall socket, AF_INET4, SOCK_STREAM, 0
test eax, eax
jz .error3
cmp eax, -1
je .error3
mov [socketnum], eax
DEBUGF 1, "Socket: 0x%x\n", eax
; Connect to the server
mcall connect, [socketnum], [sockaddr], 18
test eax, eax
jnz .error3
jnz .error4
DEBUGF 1, "Socket is now connected.\n"
invoke freeaddrinfo ; Free allocated memory
mov eax, [socketnum]
ret
.error4:
mcall close, [socketnum]
.error3:
DEBUGF 2, "Could not connect to the remote server\n"
invoke freeaddrinfo ; Free allocated memory
@@ -501,7 +501,8 @@ img.decode.jpg:
jnz .no_create_palette
push ecx edi
mov edi, [eax + Image.Palette]
xor eax, eax
mov eax, 0xFF000000 ; opaque, like the palettes of the other decoders:
; converted to 32 bpp, alpha 0 made the picture invisible
mov ecx, 256
@@:
stosd
+9 -4
View File
@@ -1,5 +1,6 @@
format MS COFF
public EXPORTS
include '../../../KOSfuncs.inc'
section '.flat' code readable align 16
; void __stdcall START(dword state);
DLL_ENTRY equ 1
@@ -60,6 +61,7 @@ START:
; SORT_BY_ACCESSED = 12, SORT_BY_ACCESSED_REV = 13 };
; int __stdcall sort_dir(BDFE* folder_data, unsigned num_folder_entries, sort_mode mode);
; return: 0 = ok, 1 = error
align 4
sort_dir:
cmp dword [esp+12], num_compare_fns
jae .error
@@ -73,9 +75,9 @@ sort_dir:
jz .done
cmp eax, ecx
jae .memok
push 68
push SF_SYS_MISC
pop eax
push 12
push SSF_MEM_ALLOC
pop ebx
int 0x40
test eax, eax
@@ -103,6 +105,8 @@ sort_dir:
pop ecx
mov ebx, edx
sub esp, 304
cld
align 4
.moveloop:
mov esi, [ebx]
test esi, esi
@@ -139,9 +143,9 @@ sort_dir:
.done_free:
cmp edx, ptr_table
jz .done
push 68
push SF_SYS_MISC
pop eax
push 13
push SSF_MEM_FREE
pop ebx
mov ecx, edx
int 0x40
@@ -269,6 +273,7 @@ compare_name_rev:
stc
ret
align 4
strcmpi:
push eax
@@:
+4
View File
@@ -1,6 +1,10 @@
HISTORY:
4.1.1 (18/09/2026, Leency)
bug-fixes:
- fixed crash on deleting the whole text (Ctrl+A, Del)
4.1 (17/07/2015, Pathoswithin)
- various fixes
+3 -3
View File
@@ -5,8 +5,8 @@
; project name: TINYPAD
; compiler: flat assembler 1.67.21
; memory to compile: 3.0/9.0 MBytes (without/with size optimizations)
; version: SVN (4.1)
; last update: 2015-07-17 (Jul 17, 2015)
; version: SVN (4.1.1)
; last update: 2026-09-18 (Sep 18, 2026)
; minimal kernel: revision #4199 (https://git.kolibrios.org/KolibriOS/kolibrios/src/branch/main/kernel/trunk)
;-----------------------------------------------------------------------------
; originally by: Ville Michael Turjanmaa >> villemt@aton.co.jyu.fi
@@ -40,7 +40,7 @@ include 'tinypad.inc'
__header '01',1,@CODE,TINYPAD_END,STATIC_MEM_END,MAIN_STACK,@PARAMS,ini_path
APP_VERSION equ '4.1'
APP_VERSION equ '4.1.1'
TRUE = 1
FALSE = 0
+30 -1
View File
@@ -355,7 +355,7 @@ proc line_add_spaces ;////////////////////////////////////////////////////////
; ESI = line offset
; ECX = needed line length
; Output:
; EAX = delta
; EAX = delta, CF = 1 on failure
;-----------------------------------------------------------------------------
xor eax,eax
pushad
@@ -365,6 +365,7 @@ proc line_add_spaces ;////////////////////////////////////////////////////////
sub ecx,edx
lea eax,[ecx+sizeof.EDITOR_LINE_DATA]
call editor_realloc_lines
jc .failed
mov [esp+4*7],eax
add esi,eax
push ecx
@@ -388,6 +389,26 @@ proc line_add_spaces ;////////////////////////////////////////////////////////
rep stosb
.exit:
popad
clc
ret
.failed:
popad
stc
ret
endp
;-----------------------------------------------------------------------------
proc set_lines_terminator ;///////////////////////////////////////////////////
;-----------------------------------------------------------------------------
; Lines buffer is terminated by a line header with zero Size, restore it after
; the data has been compacted (line count decreased)
;-----------------------------------------------------------------------------
push ecx esi
mov ecx,[cur_editor.Lines.Count]
call get_line_offset
mov [esi+EDITOR_LINE_DATA.Size],0
mov [esi+EDITOR_LINE_DATA.Flags],0
pop esi ecx
ret
endp
@@ -408,6 +429,7 @@ proc delete_selection ;///////////////////////////////////////////////////////
or [esi+EDITOR_LINE_DATA.Flags],EDITOR_LINE_FLAG_MOFIFIED
mov ecx,[sel.begin.x]
call line_add_spaces
jc .abort
add esi,eax
lea edi,[esi+sizeof.EDITOR_LINE_DATA]
mov ecx,[sel.end.y]
@@ -456,6 +478,8 @@ proc delete_selection ;///////////////////////////////////////////////////////
rep movsb
.exit:
call set_lines_terminator
mov eax,[sel.begin.x]
mov [cur_editor.Caret.X],eax
mov [cur_editor.SelStart.X],eax
@@ -478,6 +502,11 @@ proc delete_selection ;///////////////////////////////////////////////////////
clc
ret
.abort:
popad
clc
ret
.exit.2:
stc
ret
+13
View File
@@ -993,17 +993,30 @@ endp
proc editor_realloc_lines ;///// ADD $DELTA$ TO LINES SIZE ///////////////////
;-----------------------------------------------------------------------------
; EAX = delta
; Output:
; EAX = buffer displacement, CF = 1 on failure (buffer left untouched)
;-----------------------------------------------------------------------------
push ebx ecx
mov ebx,[cur_editor.Lines.Size]
push ebx
add ebx,eax
mov eax,[cur_editor.Lines]
mov [cur_editor.Lines.Size],ebx
mov ecx,eax
stdcall mem.ReAlloc,eax,ebx
test eax,eax
jz .failed
add esp,4
mov [cur_editor.Lines],eax
sub eax,ecx
pop ecx ebx
clc
ret
.failed:
pop [cur_editor.Lines.Size]
xor eax,eax
pop ecx ebx
stc
ret
endp
+1
View File
@@ -237,6 +237,7 @@ proc load_from_memory ;///////////////////////////////////////////////////////
lea edx,[ebx+ecx]
imul ebx,eax,16
add ebx,edx
add ebx,sizeof.EDITOR_LINE_DATA
mov [ebp+EDITOR.Lines.Size],ebx
stdcall mem.ReAlloc,[ebp+EDITOR.Lines],ebx
mov [ebp+EDITOR.Lines],eax
+14
View File
@@ -591,10 +591,12 @@ proc key.ctrl_v ;///// PASTE ///////////////////////////////////
mov eax,[copy_size]
sub eax,sizeof.EDITOR_LINE_DATA
call editor_realloc_lines
jc .exit_1
mov ecx,[cur_editor.Caret.Y]
call get_line_offset
mov ecx,[cur_editor.Caret.X]
call line_add_spaces
jc .exit_1
pushd [esi+EDITOR_LINE_DATA.Size]
push esi
lea eax,[esi+ecx+sizeof.EDITOR_LINE_DATA]
@@ -692,6 +694,7 @@ proc key.ctrl_d ;///// INSERT SEPARATOR ////////////////////////
;---------------------------------------------------------------
mov eax,90+sizeof.EDITOR_LINE_DATA
call editor_realloc_lines
jc .exit
mov ecx,[cur_editor.Caret.Y]
call get_line_offset
@@ -748,6 +751,7 @@ proc key.ctrl_y ;///// DELETE CURRENT LINE /////////////////////
shr ecx,2
cld
rep movsd
call set_lines_terminator
pop eax
add eax,sizeof.EDITOR_LINE_DATA
@@ -1151,6 +1155,7 @@ proc key.del ;///// DELETE NEXT CHAR OR SELECTION //////////////
.ok.dec.lines:
dec [cur_editor.Lines.Count]
call set_lines_terminator
mov eax,[cur_editor.Lines.Count]
cmp [cur_editor.Caret.Y],eax
jb @f
@@ -1264,6 +1269,7 @@ proc key.tab ;///// TABULATE ///////////////////////////////////
push eax
call editor_realloc_lines
pop eax
jc .failed
mov ecx,[cur_editor.Caret.Y]
call get_line_offset
and [esi+EDITOR_LINE_DATA.Flags],not EDITOR_LINE_FLAG_SAVED
@@ -1282,6 +1288,7 @@ proc key.tab ;///// TABULATE ///////////////////////////////////
push eax
mov eax,10
call editor_realloc_lines
jc .failed.1
add esi,eax
pop eax
pushad
@@ -1332,6 +1339,12 @@ proc key.tab ;///// TABULATE ///////////////////////////////////
.exit:
ret
.failed.1:
pop eax
.failed:
add esp,4*2
ret
endp
;---------------------------------------------------------------
@@ -1342,6 +1355,7 @@ proc key.return ;///// CARRIAGE RETURN /////////////////////////
; so you should do a little more value
mov eax,14*100
call editor_realloc_lines
jc .exit
mov ecx,[cur_editor.Caret.Y]
call get_line_offset
+34 -25
View File
@@ -51,6 +51,7 @@ include '../../load_lib.mac'
include '../../dll.inc'
include '../../develop/libraries/libs-dev/libio/libio.inc'
include '../../develop/libraries/libs-dev/libimg/libimg.inc'
include '../../develop/libraries/box_lib/box_lib.mac'
;include '../../debug.inc'
@use_library mem.Alloc,mem.Free,mem.ReAlloc,dll.Load
@@ -63,15 +64,16 @@ ci_offs_skin_w equ 5 ;adjustment to the width of the skin frame
ci_offs_skin_h equ 24 ;skin height adjustment
; main window
ci_wnd_min_siz_x equ 585 ;minimum size x
ci_wnd_min_siz_y equ 400 ;minimum size y
ci_wnd_start_siz_x equ 585
ci_wnd_start_siz_y equ 400
ci_wnd_min_siz_x equ 510 ;minimum size x
ci_wnd_min_siz_y equ 180 ;minimum size y
; toolbar
ci_panel_x_pos equ 0 ;coord. x for panel
ci_panel_y_pos equ 20 ;coord. y for panel
ci_panel_but_y1 equ ci_panel_y_pos +5 ;y coordinate for 1st row of buttons
ci_panel_but_y2 equ ci_panel_y_pos+30 ;y coordinate for 2nd row of buttons
ci_palete_y_pos equ ci_panel_y_pos+51 ;y coordinate for color palette
ci_panel_zoom_x equ 178 ;x coordinate for zoom bar buttons
; editor window
@@ -80,7 +82,7 @@ ci_edit_wnd_y_pos equ 71 ;y coordinate for editor window
ci_edit_wnd_border equ 3 ;frame around the editor window
; scrolling
ci_scroll_dim equ 22 ;scroll sizes
ci_scroll_dim equ 16 ;scroll sizes
ci_scrollh_coord_x_min equ (ci_edit_wnd_x_pos+3) ;x minimum slider position
;horizontal scrolling
ci_scrollv_coord_y_min equ (ci_edit_wnd_y_pos+3) ;y minimum slider position
@@ -149,6 +151,12 @@ include 'init_data.inc'
;OpenDialog initialisation
stdcall [OpenDialog_Init], OpenDialog_data
stdcall [ColorDialog_Init], ColorDialog_data
mcall SF_REDRAW,SSF_BEGIN_DRAW
mov ebx,50 shl 16 + ci_wnd_start_siz_x
mov ecx,50 shl 16 + ci_wnd_start_siz_y
mcall SF_CREATE_WINDOW,,,0x73aabbcc,,name_of_program
mcall SF_REDRAW,SSF_END_DRAW
;---------------------------------------------------------------------
align 4
@@ -161,16 +169,16 @@ align 4
still:
mcall SF_WAIT_EVENT
cmp eax,1
cmp eax,EV_REDRAW
je red
cmp eax,2
cmp eax,EV_KEY
je keys
cmp eax,3
cmp eax,EV_BUTTON
je buttons
cmp eax,6
cmp eax,EV_MOUSE
je mouse
jmp still
@@ -186,7 +194,16 @@ copy_str_1:
jnz @b
ret
;---------------------------------------------------------------------
include 'events.inc'
;description:
; move both scrollbars back to the top left corner (0,0)
align 4
scrollbar_move_00:
and [PosX],0
and [PosY],0
mov [sb_horizont.position],0
mov [sb_vertical.position],0
ret
;---------------------------------------------------------------------
include 'events_of_window.inc'
include 'events_of_keys.inc'
include 'events_of_buttons.inc'
@@ -205,7 +222,6 @@ include 'menu.inc'
;-----------------------------------------------------------
;------------variables and data of program------------------
;-----------------------------------------------------------
;sound_havent_memory db 150,64,0
include 'lib_data.inc'
include 'panel_data.inc'
@@ -240,6 +256,13 @@ spray_cursor:
file 'cursors/spray.cur'
zoom_cursor:
file 'cursors/zoom.cur'
align 4
scroll_drag dd 0
sb_horizont scrollbar ci_wnd_start_siz_x-ci_scroll_dim-2*ci_offs_skin_w,0,\
ci_scroll_dim,ci_edit_wnd_y_pos+284, 15, 100,30,0, 0xaaaaaa, 0xcccccc,0, 1
sb_vertical scrollbar ci_scroll_dim,ci_wnd_start_siz_x-ci_scroll_dim-2*ci_offs_skin_w,\
284,ci_edit_wnd_y_pos, 15, 100,30,0, 0xaaaaaa, 0xcccccc,0, 1
;----------------------------------------------------------
align 4
IM_END:
@@ -305,20 +328,6 @@ counter2 rd 1
number_panel rd 1
number_menu rd 1
Scroll1CoordinatX rd 1 ;scroll x screen position
Scroll1CoordinatY rd 1 ;scroll y screen position
Scroll1MaxSizeX rd 1
Scroll1MaxSizeY rd 1
Scroll1SizeX rd 1 ;scroll polzunok size
Scroll1FreeX rd 1
Scroll2CoordinatX rd 1
Scroll2CoordinatY rd 1
Scroll2MaxSizeX rd 1
Scroll2MaxSizeY rd 1
Scroll2SizeY rd 1
Scroll2FreeY rd 1
x rd 1
y rd 1
@@ -366,7 +375,7 @@ filename_area rb 256
temp_dir_pach rb 4096
library_path rb 4096
cur_dir_path rb 4096
procinfo: rb 1024
procinfo process_information
align 4
syscolors rb 192
syscolors_end:
-21
View File
@@ -1,21 +0,0 @@
;----------------------------------------------------------
;---------------------sound of events----------------------
;----------------------------------------------------------
align 4
sound:
mcall SF_SPEAKER_PLAY,55
ret
;----------------------------------------------------------
;---------------------user events--------------------------
;----------------------------------------------------------
;description:
; перемещение скроллингов в левый верхний угол (0,0)
align 4
scrollbar_move_00:
and [PosX],0
and [PosY],0
mov [Scroll1CoordinatX],ci_scrollh_coord_x_min
mov [Scroll2CoordinatY],ci_scrollv_coord_y_min
ret
+33 -78
View File
@@ -1,17 +1,22 @@
;---------------------------------------------
;-------------interraction MOUSE--------------
;---------------------------------------------
align 4
mouse:
stdcall [kmainmenu_dispatch_cursorevent], [main_menu]
or ecx,-1
mcall SF_THREAD_INFO,procinfo
mov eax,[procinfo+70] ;staus of window
movzx eax,byte [procinfo.wnd_state]
test eax,100b
jne still
call GetMouseClick
bt [MouseBut],16
jnc @f
mov [scroll_drag],0
@@:
call GetMouseCoordinats
mov eax,[MouseX]
@@ -21,6 +26,11 @@ mouse:
add ecx,ci_scrollh_coord_x_min
add edx,ci_scrollv_coord_y_min
cmp [scroll_drag],1
je sb_hor_mouse
cmp [scroll_drag],2
je sb_ver_mouse
cmp eax,ecx
jae mouse_scroll
@@ -36,105 +46,50 @@ mouse_scroll:
;call GetMouseCoordinats
;interraction with horizontal scroller
mov eax,[Scroll1CoordinatX]
mov ebx,[Scroll1CoordinatY]
movzx eax,[sb_horizont.x_pos]
movzx ebx,[sb_horizont.y_pos]
mov ecx,[MouseX]
mov edx,[MouseY]
mov esi,[Scroll1MaxSizeX]
mov edi,[Scroll1MaxSizeY]
movzx esi,[sb_horizont.x_size]
movzx edi,[sb_horizont.y_size]
call columnus
test eax,eax
jz no_horizontal
mov eax,ci_scrollh_coord_x_min
mov ebx,[Scroll1CoordinatY]
mov ecx,[Scroll1MaxSizeX]
inc ecx
mov edx,ci_scroll_dim-6
mov esi,7
call draw_volume_rectangle ; horizontal scrollbar clear
mov eax,[MouseX]
mov ebx,[Scroll1SizeX]
shr ebx,1
sub eax,ebx
mov ecx,[MouseX]
add ecx,ebx
mov edx,ci_scrollh_coord_x_min
add edx,[Scroll1MaxSizeX]
mov [Scroll1CoordinatX],eax
sub eax,ci_scrollh_coord_x_min
jns no_min_scroll
mov [Scroll1CoordinatX],ci_scrollh_coord_x_min
no_min_scroll:
cmp ecx,edx
jl no_max_scroll
sub edx,ebx
sub edx,ebx
mov [Scroll1CoordinatX],edx
no_max_scroll:
mov eax,[Scroll1CoordinatX]
sub eax,ci_scrollh_coord_x_min
bt [MouseBut],8
jnc sb_hor_mouse
mov [scroll_drag],1
sb_hor_mouse:
stdcall [scrollbar_h_mouse],sb_horizont
mov eax,[sb_horizont.position]
mov ebx,[Picture_SizeX]
imul eax,ebx
mov ebx,[Scroll1MaxSizeX]
mov ebx,[sb_horizont.max_area]
cdq
idiv ebx
mov [PosX],eax
jmp no_vertical
no_horizontal:
mov eax,[Scroll2CoordinatX]
mov ebx,[Scroll2CoordinatY]
movzx eax,[sb_vertical.x_pos]
movzx ebx,[sb_vertical.y_pos]
mov ecx,[MouseX]
mov edx,[MouseY]
mov esi,[Scroll2MaxSizeX]
mov edi,[Scroll2MaxSizeY]
movzx esi,[sb_vertical.x_size]
movzx edi,[sb_vertical.y_size]
call columnus
test eax,eax
jz no_vertical
mov eax,[Scroll2CoordinatX]
mov ebx,ci_scrollv_coord_y_min
mov ecx,ci_scroll_dim-6
mov edx,[Scroll2MaxSizeY]
inc edx
mov esi,7
call draw_volume_rectangle ; vertical scrollbar clear
mov eax,[MouseY]
mov ebx,[Scroll2SizeY]
shr ebx,1
sub eax,ebx
mov ecx,[MouseY]
add ecx,ebx
mov edx,ci_scrollv_coord_y_min
add edx,[Scroll2MaxSizeY]
mov [Scroll2CoordinatY],eax
sub eax,ci_scrollv_coord_y_min
jns no_min_scroll2
mov [Scroll2CoordinatY],ci_scrollv_coord_y_min
no_min_scroll2:
cmp ecx,edx
jl no_max_scroll2
sub edx,ebx
sub edx,ebx
mov [Scroll2CoordinatY],edx
no_max_scroll2:
mov eax,[Scroll2CoordinatY]
sub eax,ci_scrollv_coord_y_min
bt [MouseBut],8
jnc sb_ver_mouse
mov [scroll_drag],2
sb_ver_mouse:
stdcall [scrollbar_v_mouse],sb_vertical
mov eax,[sb_vertical.position]
mov ebx,[Picture_SizeY]
imul eax,ebx
mov ebx,[Scroll2MaxSizeY]
mov ebx,[sb_vertical.max_area]
cdq
idiv ebx
mov [PosY],eax
+20 -24
View File
@@ -4,12 +4,11 @@
drawwin:
or ecx,-1
mcall SF_THREAD_INFO,procinfo
mov esi,procinfo
mov eax,[esi+process_information.box.left]
mov ebx,[esi+process_information.box.top]
mov ecx,[esi+process_information.box.width]
mov edx,[esi+process_information.box.height]
mov eax,[procinfo.box.left]
mov ebx,[procinfo.box.top]
mov ecx,[procinfo.box.width]
mov edx,[procinfo.box.height]
mov [Window_CordinatX],eax
mov [Window_CordinatY],ebx
@@ -23,6 +22,20 @@ drawwin:
@@:
mov [Window_SizeX],ecx
mov [Window_SizeY],edx
; keep the size alone for a rolled up window
test [procinfo.wnd_state],byte 100b
jnz .no_change
cmp ecx,[procinfo.box.width]
jne @f
cmp edx,[procinfo.box.height]
jz .no_change
@@:
push ecx edx esi
mov esi,edx
mov edx,ecx
mcall SF_CHANGE_WINDOW, -1, -1
pop esi edx ecx
.no_change:
mov [MaxWorkScreen_SizeX],ecx
mov [MaxWorkScreen_SizeY],edx
sub [MaxWorkScreen_SizeX],ci_edit_wnd_x_pos+2*ci_edit_wnd_border\
@@ -51,7 +64,7 @@ no_znak2:
add ecx, [Window_SizeY]
mcall SF_CREATE_WINDOW,,,0x73aabbcc,,name_of_program
mov eax,[procinfo+70] ;staus of window
movzx eax,byte [procinfo.wnd_state]
test eax,100b
jne .end
@@ -81,7 +94,7 @@ no_znak2:
add ebx,ci_edit_wnd_x_pos+ci_edit_wnd_border
mov edx,[Window_SizeX]
sub edx,ebx
sub edx,ci_scroll_dim+5-ci_edit_wnd_border
sub edx,ci_scroll_dim+5+ci_edit_wnd_border
shl ebx,16
mov bx,dx ;ширина бордюра
@@ -113,23 +126,6 @@ no_znak2:
;------------------------------------------------
mcall ,,<ci_edit_wnd_y_pos,ci_edit_wnd_border> ;бордюр под панелью и над окном
;------------------------------------------------
mov eax,ci_edit_wnd_x_pos
mov ebx,[Window_SizeY]
mov ecx,[Window_SizeX]
mov edx,ci_scroll_dim
mov esi,3
sub ecx,ci_scroll_dim+5+ci_edit_wnd_x_pos+ci_offs_skin_w
sub ebx,ci_scroll_dim+5+ci_offs_skin_h
call draw_volume_rectangle ; horizontal scrollbar border
;------------------------------------------------
mov eax,[Window_SizeX]
mov ebx,ci_edit_wnd_y_pos
mov ecx,ci_scroll_dim
mov edx,[Window_SizeY]
mov esi,3
sub eax,ci_scroll_dim+5+ci_offs_skin_w
sub edx,ci_scroll_dim+5+ci_edit_wnd_y_pos+ci_offs_skin_h
call draw_volume_rectangle ; vertical scrollbar border
call draw_scrollers
;------------------------------------------------
mov eax,[Window_SizeX]
+5 -45
View File
@@ -2,12 +2,14 @@
system_dir_1: db '/sys/lib/libimg.obj',0
system_dir_2 db '/sys/lib/proc_lib.obj',0
system_dir_3: db '/sys/lib/kmenu.obj',0
system_dir_4: db '/sys/lib/box_lib.obj',0
;---------------------------------------------------------------------
align 4
l_libs_start:
lib1 l_libs system_dir_1+9, library_path, system_dir_1, import_libimg
lib2 l_libs system_dir_2+9, library_path, system_dir_2, ProcLib_import
lib3 l_libs system_dir_3+9, library_path, system_dir_3, import_libkmenu
lib4 l_libs system_dir_4+9, library_path, system_dir_4, import_box_lib
end_l_libs:
;---------------------------------------------------------------------
align 4
@@ -79,51 +81,7 @@ colordialog_path:
path4 db '/sys/noname.bmp',0
;---------------------------------------------------------------------
align 4
import_libimg:
dd alib_init1
img_is_img dd aimg_is_img
img_info dd aimg_info
img_from_file dd aimg_from_file
img_to_file dd aimg_to_file
img_from_rgb dd aimg_from_rgb
img_to_rgb dd aimg_to_rgb
img_to_rgb2 dd aimg_to_rgb2
img_decode dd aimg_decode
img_encode dd aimg_encode
img_create dd aimg_create
img_destroy dd aimg_destroy
img_destroy_layer dd aimg_destroy_layer
img_count dd aimg_count
img_lock_bits dd aimg_lock_bits
img_unlock_bits dd aimg_unlock_bits
img_flip dd aimg_flip
img_flip_layer dd aimg_flip_layer
img_rotate dd aimg_rotate
img_rotate_layer dd aimg_rotate_layer
img_draw dd aimg_draw
dd 0,0
alib_init1 db 'lib_init',0
aimg_is_img db 'img_is_img',0
aimg_info db 'img_info',0
aimg_from_file db 'img_from_file',0
aimg_to_file db 'img_to_file',0
aimg_from_rgb db 'img_from_rgb',0
aimg_to_rgb db 'img_to_rgb',0
aimg_to_rgb2 db 'img_to_rgb2',0
aimg_decode db 'img_decode',0
aimg_encode db 'img_encode',0
aimg_create db 'img_create',0
aimg_destroy db 'img_destroy',0
aimg_destroy_layer db 'img_destroy_layer',0
aimg_count db 'img_count',0
aimg_lock_bits db 'img_lock_bits',0
aimg_unlock_bits db 'img_unlock_bits',0
aimg_flip db 'img_flip',0
aimg_flip_layer db 'img_flip_layer',0
aimg_rotate db 'img_rotate',0
aimg_rotate_layer db 'img_rotate_layer',0
aimg_draw db 'img_draw',0
include '../../develop/libraries/libs-dev/libimg/import.inc'
align 4
ProcLib_import:
@@ -163,4 +121,6 @@ dd 0,0
akmenuitem_new db 'kmenuitem_new',0
akmenuitem_delete db 'kmenuitem_delete',0
akmenuitem_draw db 'kmenuitem_draw',0
include '../../develop/libraries/box_lib/import.inc'
;---------------------------------------------------------------------
+1 -1
View File
@@ -1,7 +1,7 @@
;**********************************************************
;------------------TEXT DATA-------------------------------
;**********************************************************
name_of_program db 'ANIMAGE graphics editor v1.52',0
name_of_program db 'ANIMAGE graphics editor v1.53',0
mouse_pos_x db 'X='
mouse_pos_y db 'Y='
new_text1 db 'PICTURE SIZE X'
+17 -26
View File
@@ -58,18 +58,16 @@ PrintMousePos:
;----------------------------------------------------------
;------------draw lines of scoll---------------------------
;----------------------------------------------------------
align 4
draw_scrollers:
mov edi,[CounterX]
mov eax,[Scroll1CoordinatX]
mov ebx,[Window_SizeY]
sub ebx,(ci_scroll_dim-3)+5+ci_offs_skin_h
sub ebx,ci_scroll_dim+5+ci_offs_skin_h
mov ecx,[Window_SizeX]
sub ecx,ci_scroll_dim+5+4+ci_scrollh_coord_x_min+ci_offs_skin_w
mov edx,ci_scroll_dim-6
mov esi,1
mov [Scroll1CoordinatY],ebx
mov [Scroll1MaxSizeY],edx
mov [Scroll1MaxSizeX],ecx
sub ecx,ci_scroll_dim+2+ci_scrollh_coord_x_min+ci_offs_skin_w
mov [sb_horizont.y_pos],bx
mov [sb_horizont.max_area],ecx
mov [sb_horizont.x_size],cx
imul ecx,edi
push eax ebx edx
mov eax,ecx
@@ -78,22 +76,15 @@ draw_scrollers:
idiv ebx
mov ecx,eax
pop edx ebx eax
mov [Scroll1SizeX],ecx
mov edi,[Scroll1MaxSizeX]
sub edi,ecx
mov [Scroll1FreeX],edi
call draw_volume_rectangle ; horizontal scrollbar polzunok
mov [sb_horizont.cur_area],ecx
mov eax,[Window_SizeX]
sub eax,(ci_scroll_dim-3)+5+ci_offs_skin_w
mov ebx,[Scroll2CoordinatY]
mov ecx,ci_scroll_dim-6
sub eax,ci_scroll_dim+5+ci_offs_skin_w
mov edx,[Window_SizeY]
sub edx,ci_scroll_dim+5+4+ci_scrollv_coord_y_min+ci_offs_skin_h
mov esi,1
mov [Scroll2CoordinatX],eax
mov [Scroll2MaxSizeX],ecx
mov [Scroll2MaxSizeY],edx
sub edx,ci_scroll_dim+2+ci_scrollv_coord_y_min+ci_offs_skin_h
mov [sb_vertical.x_pos],ax
mov [sb_vertical.max_area],edx
mov [sb_vertical.y_size],dx
imul edx,[CounterY]
push eax ebx
@@ -103,12 +94,12 @@ draw_scrollers:
idiv ebx
mov edx,eax
pop ebx eax
mov [Scroll2SizeY],edx
mov edi,[Scroll2MaxSizeY]
sub edi,edx
mov [Scroll2FreeY],edi
call draw_volume_rectangle ; vertical scrollbar polzunok
mov [sb_vertical.cur_area],edx
mov [sb_vertical.all_redraw],1
stdcall [scrollbar_v_draw],sb_vertical
mov [sb_horizont.all_redraw],1
stdcall [scrollbar_h_draw],sb_horizont
ret
button_menu_size_x dd 0
+97 -21
View File
@@ -14,6 +14,7 @@ struct thread_data
socketnum dd ? ; Commands socket
state dd ? ; disconnected/logging in/logged in/..
passivesocknum dd ? ; when in passive mode, this is the listening socket
pasv_ports_left dd ? ; ports left to try for the current PASV
datasocketnum dd ? ; socket used for data transfers
permissions dd ? ; read/write/execute/....
buffer_ptr dd ?
@@ -136,12 +137,48 @@ socketerror:
sendFTP "425 Can't open data connection"
ret
align 4
; Close the data socket if this thread currently owns one. datasocketnum only
; holds a live socket in these two modes; in any other mode it is a handle that
; has already been closed or was never opened.
close_data_sock:
cmp [ebp + thread_data.mode], MODE_PASSIVE_OK
je @f
cmp [ebp + thread_data.mode], MODE_ACTIVE
jne .done
@@:
mov [ebp + thread_data.mode], MODE_NOTREADY
mcall close, [ebp + thread_data.datasocketnum]
mov [ebp + thread_data.datasocketnum], -1
.done:
ret
align 4
; Close the passive listening socket if one is still open. It is open only
; while waiting for the client (MODE_PASSIVE_WAIT, MODE_PASSIVE_FAILED) or after
; a failed listen, so no data connection exists and the mode drops to NOTREADY.
close_pasv_sock:
cmp [ebp + thread_data.passivesocknum], -1
je .done
mcall close, [ebp + thread_data.passivesocknum]
mov [ebp + thread_data.passivesocknum], -1
mov [ebp + thread_data.mode], MODE_NOTREADY
.done:
ret
align 4
; A data transfer failed with the file in ebx open: close the file and the data
; socket, then report the error.
transfer_error:
invoke file.close, ebx
call close_data_sock
jmp socketerror
align 4
abort_transfer:
and [ebp + thread_data.permissions], not ABORT
mov [ebp + thread_data.mode], MODE_NOTREADY
invoke file.close, ebx
mcall close, [ebp + thread_data.datasocketnum]
call close_data_sock
sendFTP "530 Transfer aborted"
ret
@@ -327,7 +364,7 @@ open_datasock:
.pasv_ok:
mov [ebp + thread_data.datasocketnum], eax
mov [ebp + thread_data.mode], MODE_PASSIVE_OK
mcall close ; [ebp + thread_data.passivesocknum]
mcall close, [ebp + thread_data.passivesocknum]
mov [ebp + thread_data.passivesocknum], -1
invoke con_write_asciiz, str_datasock
@@ -691,13 +728,13 @@ cmdLIST:
mcall send
; close the data socket..
mov [ebp + thread_data.mode], MODE_NOTREADY
mcall close, [ebp + thread_data.datasocketnum]
call close_data_sock
sendFTP "226 List OK"
ret
.nosuchdir:
call close_data_sock
sendFTP "550 Directory does not exist"
ret
@@ -793,10 +830,9 @@ cmdPASS:
align 4
cmdPASV:
; cmp [ebp + thread_data.passivesocknum], -1
; je @f
; mcall close, [ebp + thread_data.passivesocknum] ; if there is still a socket open, close it
; @@:
; Drop whatever data connection the previous PASV/PORT left behind
call close_data_sock
call close_pasv_sock
; Open a new TCP socket
mcall socket, AF_INET4, SOCK_STREAM, 0
@@ -812,7 +848,13 @@ cmdPASV:
lea edx, [ebp + thread_data.datasock]
mov esi, sizeof.thread_data.datasock
.next_port: ; TODO: break the endless loop
movzx eax, word [pasv_end]
movzx ebx, word [pasv_start]
sub eax, ebx
inc eax
mov [ebp + thread_data.pasv_ports_left], eax ; number of ports in the range
.next_port:
call nextpasvport
mov ax, [pasv_port]
xchg al, ah
@@ -820,12 +862,23 @@ cmdPASV:
mcall bind
cmp eax, -1
je .next_port
jne .bound
dec dword [ebp + thread_data.pasv_ports_left] ; only count a port once bind failed
jnz .next_port
; No usable port: the range is exhausted, or listen() refused the bound one.
; Give up instead of spinning, and drop the socket before answering 425.
.fail:
call close_data_sock
call close_pasv_sock
jmp socketerror
.bound:
; And set it to listen!
mcall listen, , 1
cmp eax, -1
je socketerror
je .fail
; Tell our thread we are ready to accept incoming calls
mov [ebp + thread_data.mode], MODE_PASSIVE_WAIT
@@ -932,6 +985,10 @@ cmdPWD:
align 4
cmdPORT:
; Drop whatever data connection the previous PASV/PORT left behind
call close_data_sock
call close_pasv_sock
; PORT a1,a2,a3,a4,p1,p2
; IP address a1.a2.a3.a4, port p1*256+p2
@@ -972,7 +1029,8 @@ align 4
cmdQUIT:
sendFTP "221 Bye!"
mcall close, [ebp + thread_data.datasocketnum]
call close_data_sock
call close_pasv_sock
mcall close, [ebp + thread_data.socketnum]
add esp, 4 ; get rid of call return address
@@ -1035,7 +1093,7 @@ cmdRETR:
lea eax, [ebp + thread_data.buffer] ; FIXME: use another buffer!! if we receive something on control connection now, we screw up!
invoke file.read, ebx, eax, BUFFERSIZE
cmp eax, -1
je .cannot_open ; FIXME: this is not the correct error
je .read_error ; FIXME: this is not the correct error
push eax
invoke con_write_asciiz, str2
@@ -1049,7 +1107,7 @@ cmdRETR:
mcall send
pop ebx ecx
cmp eax, -1
je socketerror ; FIXME: not the correct error
je transfer_error ; FIXME: not the correct error
; cmp eax, ecx
; jne not_all_byes_sent ; TODO
@@ -1061,13 +1119,15 @@ cmdRETR:
invoke con_write_asciiz, str2b
mov [ebp + thread_data.mode], MODE_NOTREADY
mcall close, [ebp + thread_data.datasocketnum]
call close_data_sock
sendFTP "226 Transfer OK, closing connection"
ret
.read_error:
invoke file.close, ebx
.cannot_open:
call close_data_sock
invoke con_set_flags, 0x0c
invoke con_write_asciiz, str_notfound
invoke con_set_flags, 0x07
@@ -1126,7 +1186,14 @@ cmdSTOR:
test eax, eax
jz .cannot_open
; STOR replaces the file: drop the previous, possibly longer contents
push eax
invoke file.truncate, eax
pop ebx
test eax, eax
js .truncate_error
push ebx
sendFTP "150 Here it comes.."
pop ebx
@@ -1142,7 +1209,7 @@ cmdSTOR:
mcall recv
pop ebx ecx
cmp eax, -1
je socketerror ; FIXME: not the correct error
je transfer_error ; FIXME: not the correct error
test eax, eax
jz @f
@@ -1154,7 +1221,7 @@ cmdSTOR:
pop edx
cmp eax, -1
je .cannot_open ; FIXME: this is not the correct error
je .write_error ; FIXME: this is not the correct error
invoke con_write_asciiz, str2
@@ -1170,8 +1237,7 @@ cmdSTOR:
invoke con_write_asciiz, str2b
mov [ebp + thread_data.mode], MODE_NOTREADY
mcall close, [ebp + thread_data.datasocketnum]
call close_data_sock
@@ -1185,10 +1251,20 @@ cmdSTOR:
sendFTP "226 Transfer OK"
ret
.write_error:
invoke file.close, ebx
.cannot_open:
call close_data_sock
sendFTP "550 No create file"
ret
.truncate_error:
invoke file.close, ebx
mov [ebp + thread_data.mode], MODE_NOTREADY
mcall close, [ebp + thread_data.datasocketnum]
sendFTP "550 Cannot truncate file"
ret
;------------------------------------------------
; "SYST"
;
+11 -1
View File
@@ -172,6 +172,14 @@ start:
invoke ini.get_int, path, str_pasv, str_end, 5000
mov [pasv_end], ax
; an inverted range would leave no port to bind, fall back to the defaults
mov ax, [pasv_start]
cmp ax, [pasv_end]
jbe @f
mov word [pasv_start], 2000
mov word [pasv_end], 5000
@@:
mov [alive], 1
mainloop:
@@ -237,6 +245,7 @@ end if
lea eax, [ebp + thread_data.buffer]
mov [ebp + thread_data.buffer_ptr], eax
mov [ebp + thread_data.passivesocknum], -1
mov [ebp + thread_data.datasocketnum], -1
sendFTP "220 Welcome to KolibriOS FTP daemon" ; fix output code
@@ -264,7 +273,7 @@ threadloop:
je .not_passive
mov [ebp + thread_data.datasocketnum], eax
mov [ebp + thread_data.mode], MODE_PASSIVE_OK
mcall close ; [ebp + thread_data.passivesocknum]
mcall close, [ebp + thread_data.passivesocknum]
mov [ebp + thread_data.passivesocknum], -1
invoke con_write_asciiz, str_datasock
@@ -447,6 +456,7 @@ import libio,\
file.open, 'file_open',\
file.read, 'file_read',\
file.write, 'file_write',\
file.truncate, 'file_truncate',\
file.close, 'file_close',\
file.find.first, 'file_find_first',\
file.find.next, 'file_find_next',\
+3
View File
@@ -1,2 +1,5 @@
if tup.getconfig("NO_FASM") ~= "" then return end
tup.rule("kpack.asm", "fasm %f %o " .. tup.getconfig("KPACK_CMD"), "kpack")
-- Native host ports (windowless in-place compressor):
tup.rule("kpackw.asm", "fasm %f %o", "kpackw.exe") -- Windows PE
tup.rule("kpackl.asm", "fasm %f %o", "kpackl") -- Linux ELF32
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
# Build the native Linux port of kpack (windowless, in-place compressor).
# Self-contained ELF32 - only FASM is needed, no gcc / no linker.
fasm kpackl.asm kpackl
chmod +x kpackl
+4
View File
@@ -0,0 +1,4 @@
@echo off
rem Build the native Windows port of kpack (no window, drag-and-drop compressor).
rem Requires FASM in PATH (or edit the line below to point at fasm.exe).
fasm -m 16384 kpackw.asm kpackw.exe
+795
View File
@@ -0,0 +1,795 @@
; kpackl = Kolibri Packer, native Linux port (no output, in-place compressor)
;
; Usage: kpackl <file>
; The file is compressed in place (overwritten).
; If the file name is "kernel.mnt" it is packed with the "Kernel" option
; (self-extracting KERNPACK format), otherwise the normal KPCK format is used.
; The program prints nothing; on any problem it just leaves the file alone.
;
; Self-contained ELF32 using raw Linux int 0x80 syscalls - no libc, no linker.
; Compression core (LZMA + calltrick) and the self-extractor stub are the
; original KolibriOS kpack sources by diamond; only the OS glue is new.
format ELF executable 3
entry _start
segment readable writeable executable
use_lzma = 1
use_calltrick1 = 40h
use_calltrick2 = 80h
; Linux i386 syscalls
sys_exit = 1
sys_read = 3
sys_write = 4
sys_open = 5
sys_close = 6
sys_lseek = 19
sys_mmap2 = 192
_start:
; ---- get the file argument (argv[1]) ------------------------------
mov eax, [esp] ; argc
cmp eax, 2
jb quit
mov esi, [esp+8] ; argv[1]
mov [infilename], esi
; ---- is the base name "kernel.mnt" ? ------------------------------
mov ebx, esi ; ebx = start of base name
.bn:
mov al, [esi]
test al, al
jz .bn_done
cmp al, '/'
jne .bn_n
inc esi
mov ebx, esi
jmp .bn
.bn_n:
inc esi
jmp .bn
.bn_done:
mov esi, ebx
mov edi, kernel_name
.cmpk:
mov al, [esi]
mov ah, [edi]
test ah, ah
jnz .notend
test al, al ; kernel_name ended: match iff input ended too
jz do_kerpack
jmp do_pack
.notend:
or al, 20h ; tolower (kernel_name is lowercase)
cmp al, ah
jne do_pack
inc esi
inc edi
jmp .cmpk
;=====================================================================
; helper: allocate ecx bytes -> eax = ptr, or eax = 0 on failure
;=====================================================================
alloc:
push ebx
push edx
push esi
push edi
push ebp
mov eax, sys_mmap2
xor ebx, ebx ; addr = NULL
mov edx, 3 ; PROT_READ|PROT_WRITE
mov esi, 22h ; MAP_PRIVATE|MAP_ANONYMOUS
or edi, -1 ; fd = -1
xor ebp, ebp ; offset = 0
int 0x80
pop ebp
pop edi
pop esi
pop edx
pop ebx
cmp eax, 0xFFFFF000 ; -4096..-1 == error
jb .ok
xor eax, eax
.ok:
ret
;=====================================================================
; Normal packing (KPCK)
;=====================================================================
do_pack:
; open input (O_RDONLY)
mov eax, sys_open
mov ebx, [infilename]
xor ecx, ecx
xor edx, edx
int 0x80
test eax, eax
js quit
mov [fd], eax
; size = lseek(fd, 0, SEEK_END)
mov eax, sys_lseek
mov ebx, [fd]
xor ecx, ecx
mov edx, 2
int 0x80
test eax, eax
jle quit
mov [insize], eax
; rewind
mov eax, sys_lseek
mov ebx, [fd]
xor ecx, ecx
xor edx, edx
int 0x80
; allocate infile
mov ecx, [insize]
call alloc
test eax, eax
jz quit
mov [infile], eax
; read
mov eax, sys_read
mov ebx, [fd]
mov ecx, [infile]
mov edx, [insize]
int 0x80
; close
mov eax, sys_close
mov ebx, [fd]
int 0x80
; maximum output size
mov eax, [insize]
shr eax, 3
add eax, [insize]
add eax, 400h
mov esi, eax ; esi = maxout (preserved across alloc)
add eax, eax
mov ecx, eax
call alloc
test eax, eax
jz quit
mov [outfile], eax
mov [outfile1], eax
mov [outfilebest], eax
add eax, esi
mov [outfile2], eax
; KPCK header
mov eax, [outfile1]
mov dword [eax], 'KPCK'
mov ecx, [insize]
mov [eax+4], ecx
; LZMA dictionary size
dec ecx
bsr eax, ecx
inc eax
cmp eax, 28
jb @f
mov eax, 28
@@:
push eax
push eax
call lzma_set_dict_size ; ret 4
pop ecx
mov eax, 1
shl eax, cl
; workmem
imul eax, 19
shr eax, 1
add eax, 509000h
mov ecx, eax
call alloc
test eax, eax
jz quit
mov [workmem], eax
; first pass: plain LZMA
mov eax, [outfile2]
mov [outfile], eax
xchg eax, edi
mov esi, [outfile1]
movsd
movsd
call pk_pack_lzma
mov [outsize], eax
mov eax, [outfile]
mov [outfilebest], eax
mov [method], use_lzma
; calltrick 1
call pk_preprocess_calltrick
test eax, eax
jz .noct1
call pk_set_outfile
call pk_pack_lzma
add eax, 5
cmp eax, [outsize]
jae .noct1
mov [outsize], eax
mov eax, [outfile]
mov [outfilebest], eax
mov [method], use_lzma or use_calltrick1
.noct1:
call pk_set_outfile
push dword [ctn]
movzx eax, byte [cti]
push eax
call pk_preprocess_calltrick2
test eax, eax
jz .noct2
call pk_set_outfile
call pk_pack_lzma
add eax, 5
cmp eax, [outsize]
jae .noct2
mov [outsize], eax
mov eax, [outfile]
mov [outfilebest], eax
mov [method], use_lzma or use_calltrick2
pop ecx
pop ecx
push dword [ctn]
movzx eax, byte [cti]
push eax
.noct2:
pop eax
mov [cti], al
pop eax
mov [ctn], eax
add dword [outsize], 12
mov eax, [outsize]
cmp eax, [insize]
jb .packed_ok
jmp quit ; not smaller: leave original
.packed_ok:
movzx eax, byte [method]
mov edi, [outfilebest]
mov [edi+8], eax
test al, use_calltrick1 or use_calltrick2
jz .save
mov ecx, [outsize]
add ecx, edi
mov eax, [ctn]
mov [ecx-5], eax
mov al, [cti]
mov [ecx-1], al
.save:
; open(name, O_WRONLY|O_CREAT|O_TRUNC, 0644)
mov eax, sys_open
mov ebx, [infilename]
mov ecx, 0x241
mov edx, 0x1A4
int 0x80
test eax, eax
js quit
mov [fd], eax
mov eax, sys_write
mov ebx, [fd]
mov ecx, [outfilebest]
mov edx, [outsize]
int 0x80
mov eax, sys_close
mov ebx, [fd]
int 0x80
quit:
mov eax, sys_exit
xor ebx, ebx
int 0x80
;---------------------------------------------------------------------
pk_set_outfile:
mov eax, [outfilebest]
xor eax, [outfile1]
xor eax, [outfile2]
mov [outfile], eax
ret
;---------------------------------------------------------------------
pk_pack_lzma:
mov eax, [outfile]
add eax, 11
push [workmem]
push [insize]
push eax
push [infile]
call lzma_compress ; ret 16
mov ecx, [outfile]
mov edx, [ecx+12]
bswap edx
mov [ecx+12], edx
dec eax
ret
;---------------------------------------------------------------------
pk_ct_fail:
xor eax, eax
mov [ctn], eax
ret
;---------------------------------------------------------------------
pk_preprocess_calltrick:
mov ecx, [insize]
call alloc
test eax, eax
jz pk_ct_fail
push eax
xor eax, eax
mov edi, ct1
mov ecx, 256/4
push edi
rep stosd
pop edi
mov ecx, [insize]
mov esi, [infile]
xchg eax, edx ; edx = 0
pop eax
xchg eax, ebx ; ebx = temp buffer
push ebx
.pre:
lodsb
sub al, 0E8h
cmp al, 1
ja .cont
cmp ecx, 5
jb .done
lodsd
add eax, esi
sub eax, [infile]
cmp eax, [insize]
jae .xxx
cmp eax, 1000000h
jae .xxx
sub ecx, 4
bswap eax
mov [esi-4], eax
inc edx
mov [ebx], esi
add ebx, 4
jmp .cont
.xxx:
sub esi, 4
movzx eax, byte [esi]
mov byte [eax+edi], 1
.cont:
loop .pre
.done:
mov [ctn], edx
pop edx ; edx = base of temp buffer
xor eax, eax
mov ecx, 256
repnz scasb
jnz pk_ct_fail
not cl
mov [cti], cl
@@:
cmp ebx, edx
jz @f
sub ebx, 4
mov eax, [ebx]
mov [eax-4], cl
jmp @b
@@:
mov al, 1
ret
;---------------------------------------------------------------------
pk_preprocess_calltrick2:
; restore input
mov esi, [infile]
mov ecx, [ctn]
jecxz .pre_init
.restore:
lodsb
sub al, 0E8h
cmp al, 1
ja .restore
mov al, [cti]
cmp [esi], al
jnz .restore
lodsd
mov al, 0
bswap eax
sub eax, esi
add eax, [infile]
mov [esi-4], eax
loop .restore
.pre_init:
mov ecx, [insize]
call alloc
test eax, eax
jz pk_ct_fail
mov edi, ct1
xchg eax, ebx
xor eax, eax
push edi
mov ecx, 256/4
rep stosd
pop edi
mov ecx, [insize]
mov esi, [infile]
xchg eax, edx ; edx = 0
push ebx
.pre:
lodsb
.chk0f:
cmp al, 0Fh
jnz .ip1
dec ecx
jz .done
lodsb
cmp al, 80h
jb .chk0f
cmp al, 90h
jb .take
.ip1:
sub al, 0E8h
cmp al, 1
ja .cont
.take:
cmp ecx, 5
jb .done
lodsd
add eax, esi
sub eax, [infile]
cmp eax, [insize]
jae .xxx
cmp eax, 1000000h
jae .xxx
sub ecx, 4
bswap eax
mov [esi-4], eax
inc edx
mov [ebx], esi
add ebx, 4
jmp .cont
.xxx:
sub esi, 4
movzx eax, byte [esi]
mov byte [eax+edi], 1
.cont:
loop .pre
.done:
mov [ctn], edx
pop edx
xor eax, eax
mov ecx, 256
repnz scasb
jnz pk_ct_fail
not cl
mov [cti], cl
@@:
cmp ebx, edx
jz @f
sub ebx, 4
mov eax, [ebx]
mov [eax-4], cl
jmp @b
@@:
mov al, 1
ret
;=====================================================================
; Kernel packing (self-extracting KERNPACK)
;=====================================================================
do_kerpack:
mov ecx, 300*1024*3 + 6A8000h
call alloc
test eax, eax
jz quit
mov [infile], eax
add eax, 300*1024
mov [inbuftmp], eax
add eax, 300*1024
mov [outfile], eax
add eax, 300*1024
mov [workmem], eax
; open + read
mov eax, sys_open
mov ebx, [infilename]
xor ecx, ecx
xor edx, edx
int 0x80
test eax, eax
js quit
mov [fd], eax
mov eax, sys_lseek
mov ebx, [fd]
xor ecx, ecx
mov edx, 2
int 0x80
test eax, eax
jle quit
cmp eax, 300*1024
jbe @f
mov eax, 300*1024
@@:
mov [insize3], eax
mov eax, sys_lseek
mov ebx, [fd]
xor ecx, ecx
xor edx, edx
int 0x80
mov eax, sys_read
mov ebx, [fd]
mov ecx, [infile]
mov edx, [insize3]
int 0x80
mov eax, sys_close
mov ebx, [fd]
int 0x80
; already packed?
mov ebx, [insize3]
mov edi, [infile]
add edi, ebx
cmp dword [edi-8], 'KERN'
jnz .go
cmp dword [edi-4], 'PACK'
jz quit
.go:
push 18
call lzma_set_dict_size
; find jump to 32-bit code
mov edi, [infile]
mov eax, edi
add eax, [insize3]
dec edi
.find:
cmp eax, edi
je quit ; not a kernel
inc edi
cmp dword [edi], 0xE88EE08E ; mov fs,ax / mov gs,ax
jnz .find
cmp dword [edi+4], 0x00BCD08E ; mov ss,ax / mov esp,00xxxxxx
jnz .find
add edi, 11
mov [inptr], edi
sub edi, [infile]
mov [indelta], edi
lea eax, [ebx+0x10000]
mov dword [loader_patch3+2], eax
sub ebx, edi
mov [insize1], ebx
call ker_preprocess_calltrick3
mov al, [cti]
mov [loader_patch5-1], al
mov eax, [ctn]
mov [loader_patch4+1], eax
mov eax, [inptr]
add eax, [outfile]
sub eax, [infile]
add eax, loader_size - 5
push [workmem]
push [insize1]
push eax
push [inptr]
call lzma_compress
add eax, loader_size - 5
mov [loader_patch1+6], eax
add eax, [indelta]
mov [outsize3], eax
mov eax, [indelta]
mov ecx, eax
add ecx, [outfile]
mov ecx, [ecx + loader_size - 4]
bswap ecx
mov [loader_patch2+4], ecx
add eax, 0x10000
mov [loader_patch1+1], eax
mov esi, [infile]
mov edi, [outfile]
mov ecx, [indelta]
rep movsb
mov esi, loader_start
mov ecx, loader_size
rep movsb
mov eax, [outfile]
add eax, [outsize3]
mov dword [eax], 'KERN'
mov dword [eax+4], 'PACK'
add dword [outsize3], 8
; save
mov eax, sys_open
mov ebx, [infilename]
mov ecx, 0x241
mov edx, 0x1A4
int 0x80
test eax, eax
js quit
mov [fd], eax
mov eax, sys_write
mov ebx, [fd]
mov ecx, [outfile]
mov edx, [outsize3]
int 0x80
mov eax, sys_close
mov ebx, [fd]
int 0x80
jmp quit
;---------------------------------------------------------------------
ker_preprocess_calltrick3:
mov edi, ct1
xor eax, eax
push edi
mov ecx, 256/4
rep stosd
pop edi
mov ecx, ebx ; ecx = insize1
mov esi, [inptr]
mov ebx, [inbuftmp]
xchg eax, edx ; edx = 0
.pre:
lodsb
.chk0f:
cmp al, 0Fh
jnz .ip1
dec ecx
jz .done
lodsb
cmp al, 80h
jb .chk0f
cmp al, 90h
jb .take
.ip1:
sub al, 0E8h
cmp al, 1
ja .cont
.take:
cmp ecx, 5
jb .done
lodsd
add eax, esi
sub eax, [inptr]
cmp eax, [insize1]
jae .xxx
cmp eax, 1000000h
jae .xxx
sub ecx, 4
bswap eax
mov [esi-4], eax
inc edx
mov [ebx], esi
add ebx, 4
jmp .cont
.xxx:
sub esi, 4
movzx eax, byte [esi]
mov byte [eax+edi], 1
.cont:
loop .pre
.done:
mov [ctn], edx
xor eax, eax
mov ecx, 256
repnz scasb
jnz .ret
not cl
mov [cti], cl
@@:
cmp ebx, [inbuftmp]
jz .ret
sub ebx, 4
mov eax, [ebx]
mov [eax-4], cl
jmp @b
.ret:
ret
;---------------------------------------------------------------------
; LZMA compressor and the self-extractor stub (original diamond code)
;---------------------------------------------------------------------
include 'lzma_compress.inc'
include 'lzma_set_dict_size.inc'
include 'loader_lzma.inc'
;---------------------------------------------------------------------
; initialized data
;---------------------------------------------------------------------
kernel_name db 'kernel.mnt', 0
align 4
LiteralNextStates:
db 0,0,0,0,1,2,3,4,5,6,4,5
MatchNextStates:
db 7,7,7,7,7,7,7,10,10,10,10,10
RepNextStates:
db 8,8,8,8,8,8,8,11,11,11,11,11
ShortRepNextStates:
db 9,9,9,9,9,9,9,11,11,11,11,11
align 4
method db 1
;---------------------------------------------------------------------
; uninitialized data (BSS - must stay at the very end of the segment)
;---------------------------------------------------------------------
align 4
infilename dd ?
fd dd ?
infile dd ?
outfile dd ?
outfile1 dd ?
outfile2 dd ?
outfilebest dd ?
inbuftmp dd ?
workmem dd ?
insize dd ?
outsize dd ?
insize3 dd ?
outsize3 dd ?
inptr dd ?
indelta dd ?
insize1 dd ?
ctn dd ?
cti db ?
db 0,0,0
ct1 rb 256
align 4
; LZMA compressor work area (from kpack data.inc) - referenced by name
; from lzma_compress.inc; must keep this exact layout.
_lenEncoder: rd 8451
_prices: rd 4384
rd 17
_finished: rb 1
_writeEndMark: rb 1
_longestMatchWasFound: rb 1
_previousByte: rb 1
_longestMatchLength: rd 1
g_FastPos: rb 1024
_posSlotPrices: rd 256
_isRep0Long: rd 192
distances: rd 274
_optimumCurrentIndex: rd 1
_additionalOffset: rd 1
_isRepG1: rd 12
_isMatch: rd 192
_alignPriceCount: rd 1
_numLiteralContextBits: rd 1
_literalEncoder: rd 114
nowPos64: rd 2
_distancesPrices: rd 512
_repDistances: rd 4
_posSlotEncoder: rd 1028
lastPosSlotFillingPos: rd 2
_numFastBytes: rd 1
_posStateMask: rd 1
_isRepG0: rd 12
_repMatchLenEncoder: rd 8451
rd 4384
rd 17
_isRepG2: rd 12
_dictionarySize: rd 1
_numLiteralPosStateBits:rd 1
_distTableSize: rd 1
_optimumEndIndex: rd 1
state.State: rb 1
state.Prev1IsChar: rb 1
state.Prev2: rb 2
state.PosPrev2: rd 1
state.BackPrev2: rd 1
state.Price: rd 1
state.PosPrev: rd 1
state.BackPrev: rd 1
state.Backs: rd 4
rd 40950
_alignPrices: rd 16
_isRep: rd 12
_posAlignEncoder: rd 256
i_01: rd 1
_state: rb 1
_cache: rb 1
_state.Prev2: rb 2
_posEncoders: rd 1
_numPrevBits: rd 1
_numPosBits: rd 1
_posMask: rd 1
_posStateBits: rd 1
_range: rd 1
_cacheSize: rd 1
_cyclicBufferSize: rd 1
low: rd 2
Models: rd 512
_matchMaxLen: rd 1
pack_pos: rd 1
_cutValue: rd 1
_hash: rd 1
crc_table: rd 256
_buffer: rd 1
_pos: rd 1
_streamPos: rd 1
pack_length: rd 1
+890
View File
@@ -0,0 +1,890 @@
; kpackw = Kolibri Packer, native Windows port (no window, not even a console)
;
; Usage: drag a file onto kpackw.exe, or kpackw.exe <file>
; The file is compressed in place (overwritten).
; If the file name is "kernel.mnt" it is packed with the "Kernel" option
; (self-extracting KERNPACK format), otherwise the normal KPCK format is used.
;
; Compression core (LZMA + calltrick) and the self-extractor stub are the
; original KolibriOS kpack sources by diamond; only the OS glue is new.
format PE GUI 4.0
entry start
;=====================================================================
section '.text' code readable writeable executable
;=====================================================================
use_lzma = 1
use_calltrick1 = 40h
use_calltrick2 = 80h
start:
; ---- get command line, extract the file argument ------------------
call [GetCommandLineA]
mov esi, eax
; skip leading spaces
.skip1:
mov al, [esi]
cmp al, ' '
jne .arg0
inc esi
jmp .skip1
; skip program name (argv[0])
.arg0:
cmp byte [esi], '"'
jne .arg0_plain
inc esi
.arg0_q:
mov al, [esi]
test al, al
jz .no_arg
inc esi
cmp al, '"'
jne .arg0_q
jmp .skip2
.arg0_plain:
mov al, [esi]
test al, al
jz .no_arg
cmp al, ' '
je .skip2
inc esi
jmp .arg0_plain
; skip spaces between argv[0] and argv[1]
.skip2:
mov al, [esi]
cmp al, ' '
jne .arg1
inc esi
jmp .skip2
; read the file name argument into infilename
.arg1:
mov al, [esi]
test al, al
jz .no_arg
mov edi, infilename
cmp al, '"'
jne .arg1_plain
inc esi
.arg1_q:
mov al, [esi]
test al, al
jz .name_done
inc esi
cmp al, '"'
je .name_done
stosb
jmp .arg1_q
.arg1_plain:
mov al, [esi]
test al, al
jz .name_done
cmp al, ' '
je .name_done
inc esi
stosb
jmp .arg1_plain
.name_done:
mov byte [edi], 0
; ---- is the base name "kernel.mnt" ? ------------------------------
; find base name (after last '\' or '/')
mov esi, infilename
mov ebx, esi ; ebx = start of base name
.bn:
mov al, [esi]
test al, al
jz .bn_done
cmp al, '\'
je .bn_sep
cmp al, '/'
je .bn_sep
inc esi
jmp .bn
.bn_sep:
inc esi
mov ebx, esi
jmp .bn
.bn_done:
; case-insensitive compare ebx with "kernel.mnt"
mov esi, ebx
mov edi, kernel_name
.cmpk:
mov al, [esi]
mov ah, [edi]
test ah, ah
jnz .notend
test al, al ; kernel_name ended: match iff input ended too
jz do_kerpack
jmp do_pack
.notend:
or al, 20h ; tolower (kernel_name is lowercase)
cmp al, ah
jne do_pack
inc esi
inc edi
jmp .cmpk
.no_arg:
push 0
call [ExitProcess]
;=====================================================================
; Normal packing (KPCK) - transcribed from the KolibriOS/linux kpack
;=====================================================================
do_pack:
; open input
push 0
push 0
push 3 ; OPEN_EXISTING
push 0
push 1 ; FILE_SHARE_READ
push 80000000h ; GENERIC_READ
push infilename
call [CreateFileA]
cmp eax, -1
je quit
mov esi, eax ; handle
push 0
push esi
call [GetFileSize]
cmp eax, -1
je quit
test eax, eax
jz quit
mov [insize], eax
; allocate infile
push 4
push 3000h
push eax
push 0
call [VirtualAlloc]
test eax, eax
jz quit
mov [infile], eax
; read
push 0
push bytesdone
push [insize]
push eax
push esi
call [ReadFile]
test eax, eax
jz quit
push esi
call [CloseHandle]
; maximum output size
mov eax, [insize]
shr eax, 3
add eax, [insize]
add eax, 400h
mov esi, eax ; esi = maxout
add eax, eax ; two copies
push 4
push 3000h
push eax
push 0
call [VirtualAlloc]
test eax, eax
jz quit
mov [outfile], eax
mov [outfile1], eax
mov [outfilebest], eax
add eax, esi
mov [outfile2], eax
; KPCK header
mov eax, [outfile1]
mov dword [eax], 'KPCK'
mov ecx, [insize]
mov [eax+4], ecx
; LZMA dictionary size
dec ecx
bsr eax, ecx
inc eax
cmp eax, 28
jb @f
mov eax, 28
@@:
push eax
push eax
call lzma_set_dict_size ; ret 4 (pops one)
pop ecx ; ecx = log2(dict)
mov eax, 1
shl eax, cl
; workmem
imul eax, 19
shr eax, 1
add eax, 509000h
push 4
push 3000h
push eax
push 0
call [VirtualAlloc]
test eax, eax
jz quit
mov [workmem], eax
; first pass: plain LZMA
mov eax, [outfile2]
mov [outfile], eax
xchg eax, edi
mov esi, [outfile1]
movsd
movsd
call pk_pack_lzma
mov [outsize], eax
mov eax, [outfile]
mov [outfilebest], eax
mov [method], use_lzma
; calltrick 1
call pk_preprocess_calltrick
test eax, eax
jz .noct1
call pk_set_outfile
call pk_pack_lzma
add eax, 5
cmp eax, [outsize]
jae .noct1
mov [outsize], eax
mov eax, [outfile]
mov [outfilebest], eax
mov [method], use_lzma or use_calltrick1
.noct1:
call pk_set_outfile
push dword [ctn]
movzx eax, byte [cti]
push eax
call pk_preprocess_calltrick2
test eax, eax
jz .noct2
call pk_set_outfile
call pk_pack_lzma
add eax, 5
cmp eax, [outsize]
jae .noct2
mov [outsize], eax
mov eax, [outfile]
mov [outfilebest], eax
mov [method], use_lzma or use_calltrick2
pop ecx
pop ecx
push dword [ctn]
movzx eax, byte [cti]
push eax
.noct2:
pop eax
mov [cti], al
pop eax
mov [ctn], eax
add dword [outsize], 12
mov eax, [outsize]
cmp eax, [insize]
jb .packed_ok
jmp quit ; output not smaller: leave original untouched
.packed_ok:
movzx eax, byte [method]
mov edi, [outfilebest]
mov [edi+8], eax
test al, use_calltrick1 or use_calltrick2
jz .save
mov ecx, [outsize]
add ecx, edi
mov eax, [ctn]
mov [ecx-5], eax
mov al, [cti]
mov [ecx-1], al
.save:
push 0
push 80h ; FILE_ATTRIBUTE_NORMAL
push 2 ; CREATE_ALWAYS
push 0
push 0
push 40000000h ; GENERIC_WRITE
push infilename
call [CreateFileA]
cmp eax, -1
je quit
mov esi, eax
push 0
push bytesdone
push [outsize]
push [outfilebest]
push esi
call [WriteFile]
push esi
call [CloseHandle]
quit:
push 0
call [ExitProcess]
;---------------------------------------------------------------------
pk_set_outfile:
mov eax, [outfilebest]
xor eax, [outfile1]
xor eax, [outfile2]
mov [outfile], eax
ret
;---------------------------------------------------------------------
pk_pack_lzma:
mov eax, [outfile]
add eax, 11
push [workmem]
push [insize]
push eax
push [infile]
call lzma_compress ; ret 16
mov ecx, [outfile]
mov edx, [ecx+12]
bswap edx
mov [ecx+12], edx
dec eax
ret
;---------------------------------------------------------------------
pk_ct_fail:
xor eax, eax
mov [ctn], eax
ret
;---------------------------------------------------------------------
pk_preprocess_calltrick:
push 4
push 3000h
push [insize]
push 0
call [VirtualAlloc]
test eax, eax
jz pk_ct_fail
push eax
xor eax, eax
mov edi, ct1
mov ecx, 256/4
push edi
rep stosd
pop edi
mov ecx, [insize]
mov esi, [infile]
xchg eax, edx ; edx = 0
pop eax
xchg eax, ebx ; ebx = temp buffer
push ebx
.pre:
lodsb
sub al, 0E8h
cmp al, 1
ja .cont
cmp ecx, 5
jb .done
lodsd
add eax, esi
sub eax, [infile]
cmp eax, [insize]
jae .xxx
cmp eax, 1000000h
jae .xxx
sub ecx, 4
bswap eax
mov [esi-4], eax
inc edx
mov [ebx], esi
add ebx, 4
jmp .cont
.xxx:
sub esi, 4
movzx eax, byte [esi]
mov byte [eax+edi], 1
.cont:
loop .pre
.done:
mov [ctn], edx
pop edx ; edx = base of temp buffer
xor eax, eax
mov ecx, 256
repnz scasb
jnz pk_ct_fail
not cl
mov [cti], cl
@@:
cmp ebx, edx
jz @f
sub ebx, 4
mov eax, [ebx]
mov [eax-4], cl
jmp @b
@@:
mov al, 1
ret
;---------------------------------------------------------------------
pk_preprocess_calltrick2:
; restore input
mov esi, [infile]
mov ecx, [ctn]
jecxz .pre_init
.restore:
lodsb
sub al, 0E8h
cmp al, 1
ja .restore
mov al, [cti]
cmp [esi], al
jnz .restore
lodsd
mov al, 0
bswap eax
sub eax, esi
add eax, [infile]
mov [esi-4], eax
loop .restore
.pre_init:
push 4
push 3000h
push [insize]
push 0
call [VirtualAlloc]
test eax, eax
jz pk_ct_fail
mov edi, ct1
xchg eax, ebx
xor eax, eax
push edi
mov ecx, 256/4
rep stosd
pop edi
mov ecx, [insize]
mov esi, [infile]
xchg eax, edx ; edx = 0
push ebx
.pre:
lodsb
.chk0f:
cmp al, 0Fh
jnz .ip1
dec ecx
jz .done
lodsb
cmp al, 80h
jb .chk0f
cmp al, 90h
jb .take
.ip1:
sub al, 0E8h
cmp al, 1
ja .cont
.take:
cmp ecx, 5
jb .done
lodsd
add eax, esi
sub eax, [infile]
cmp eax, [insize]
jae .xxx
cmp eax, 1000000h
jae .xxx
sub ecx, 4
bswap eax
mov [esi-4], eax
inc edx
mov [ebx], esi
add ebx, 4
jmp .cont
.xxx:
sub esi, 4
movzx eax, byte [esi]
mov byte [eax+edi], 1
.cont:
loop .pre
.done:
mov [ctn], edx
pop edx
xor eax, eax
mov ecx, 256
repnz scasb
jnz pk_ct_fail
not cl
mov [cti], cl
@@:
cmp ebx, edx
jz @f
sub ebx, 4
mov eax, [ebx]
mov [eax-4], cl
jmp @b
@@:
mov al, 1
ret
;=====================================================================
; Kernel packing (self-extracting KERNPACK) - from kerpack.inc
;=====================================================================
do_kerpack:
push 4
push 3000h
push 300*1024*3 + 6A8000h
push 0
call [VirtualAlloc]
test eax, eax
jz quit
mov [infile], eax
add eax, 300*1024
mov [inbuftmp], eax
add eax, 300*1024
mov [outfile], eax
add eax, 300*1024
mov [workmem], eax
; open + read
push 0
push 0
push 3
push 0
push 1
push 80000000h
push infilename
call [CreateFileA]
cmp eax, -1
je quit
mov esi, eax
push 0
push esi
call [GetFileSize]
cmp eax, -1
je quit
test eax, eax
jz quit
cmp eax, 300*1024
jbe @f
mov eax, 300*1024
@@:
mov [insize3], eax
push 0
push bytesdone
push [insize3]
push [infile]
push esi
call [ReadFile]
push esi
call [CloseHandle]
; already packed?
mov ebx, [insize3]
mov edi, [infile]
add edi, ebx
cmp dword [edi-8], 'KERN'
jnz .go
cmp dword [edi-4], 'PACK'
jz quit
.go:
push 18
call lzma_set_dict_size
; find jump to 32-bit code
mov edi, [infile]
mov eax, edi
add eax, [insize3]
dec edi
.find:
cmp eax, edi
je quit ; not a kernel
inc edi
cmp dword [edi], 0xE88EE08E ; mov fs,ax / mov gs,ax
jnz .find
cmp dword [edi+4], 0x00BCD08E ; mov ss,ax / mov esp,00xxxxxx
jnz .find
add edi, 11
mov [inptr], edi
sub edi, [infile]
mov [indelta], edi
lea eax, [ebx+0x10000]
mov dword [loader_patch3+2], eax
sub ebx, edi
mov [insize1], ebx
call ker_preprocess_calltrick3
mov al, [cti]
mov [loader_patch5-1], al
mov eax, [ctn]
mov [loader_patch4+1], eax
mov eax, [inptr]
add eax, [outfile]
sub eax, [infile]
add eax, loader_size - 5
push [workmem]
push [insize1]
push eax
push [inptr]
call lzma_compress
add eax, loader_size - 5
mov [loader_patch1+6], eax
add eax, [indelta]
mov [outsize3], eax
mov eax, [indelta]
mov ecx, eax
add ecx, [outfile]
mov ecx, [ecx + loader_size - 4]
bswap ecx
mov [loader_patch2+4], ecx
add eax, 0x10000
mov [loader_patch1+1], eax
mov esi, [infile]
mov edi, [outfile]
mov ecx, [indelta]
rep movsb
mov esi, loader_start
mov ecx, loader_size
rep movsb
mov eax, [outfile]
add eax, [outsize3]
mov dword [eax], 'KERN'
mov dword [eax+4], 'PACK'
add dword [outsize3], 8
; save
push 0
push 80h
push 2
push 0
push 0
push 40000000h
push infilename
call [CreateFileA]
cmp eax, -1
je quit
mov esi, eax
push 0
push bytesdone
push [outsize3]
push [outfile]
push esi
call [WriteFile]
push esi
call [CloseHandle]
jmp quit
;---------------------------------------------------------------------
ker_preprocess_calltrick3:
mov edi, ct1
xor eax, eax
push edi
mov ecx, 256/4
rep stosd
pop edi
mov ecx, ebx ; ecx = insize1
mov esi, [inptr]
mov ebx, [inbuftmp]
xchg eax, edx ; edx = 0
.pre:
lodsb
.chk0f:
cmp al, 0Fh
jnz .ip1
dec ecx
jz .done
lodsb
cmp al, 80h
jb .chk0f
cmp al, 90h
jb .take
.ip1:
sub al, 0E8h
cmp al, 1
ja .cont
.take:
cmp ecx, 5
jb .done
lodsd
add eax, esi
sub eax, [inptr]
cmp eax, [insize1]
jae .xxx
cmp eax, 1000000h
jae .xxx
sub ecx, 4
bswap eax
mov [esi-4], eax
inc edx
mov [ebx], esi
add ebx, 4
jmp .cont
.xxx:
sub esi, 4
movzx eax, byte [esi]
mov byte [eax+edi], 1
.cont:
loop .pre
.done:
mov [ctn], edx
xor eax, eax
mov ecx, 256
repnz scasb
jnz .ret
not cl
mov [cti], cl
@@:
cmp ebx, [inbuftmp]
jz .ret
sub ebx, 4
mov eax, [ebx]
mov [eax-4], cl
jmp @b
.ret:
ret
;---------------------------------------------------------------------
; LZMA compressor and the self-extractor stub (original diamond code)
;---------------------------------------------------------------------
include 'lzma_compress.inc'
include 'lzma_set_dict_size.inc'
include 'loader_lzma.inc'
;=====================================================================
section '.data' data readable writeable
;=====================================================================
kernel_name db 'kernel.mnt', 0
align 4
; LZMA state-transition tables (constants, referenced by lzma_compress)
LiteralNextStates:
db 0,0,0,0,1,2,3,4,5,6,4,5
MatchNextStates:
db 7,7,7,7,7,7,7,10,10,10,10,10
RepNextStates:
db 8,8,8,8,8,8,8,11,11,11,11,11
ShortRepNextStates:
db 9,9,9,9,9,9,9,11,11,11,11,11
align 4
method db 1
db 0,0,0
infile dd ?
outfile dd ?
outfile1 dd ?
outfile2 dd ?
outfilebest dd ?
inbuftmp dd ?
workmem dd ?
insize dd ?
outsize dd ?
insize3 dd ?
outsize3 dd ?
inptr dd ?
indelta dd ?
insize1 dd ?
ctn dd ?
cti db ?
db 0,0,0
bytesdone dd ?
;=====================================================================
section '.bss' data readable writeable
;=====================================================================
infilename rb 1024
ct1 rb 256
align 4
;---------------------------------------------------------------------
; LZMA compressor work area (from kpack data.inc) - referenced by name
; from lzma_compress.inc; must keep this exact layout.
;---------------------------------------------------------------------
_lenEncoder: rd 8451
_prices: rd 4384
rd 17
_finished: rb 1
_writeEndMark: rb 1
_longestMatchWasFound: rb 1
_previousByte: rb 1
_longestMatchLength: rd 1
g_FastPos: rb 1024
_posSlotPrices: rd 256
_isRep0Long: rd 192
distances: rd 274
_optimumCurrentIndex: rd 1
_additionalOffset: rd 1
_isRepG1: rd 12
_isMatch: rd 192
_alignPriceCount: rd 1
_numLiteralContextBits: rd 1
_literalEncoder: rd 114
nowPos64: rd 2
_distancesPrices: rd 512
_repDistances: rd 4
_posSlotEncoder: rd 1028
lastPosSlotFillingPos: rd 2
_numFastBytes: rd 1
_posStateMask: rd 1
_isRepG0: rd 12
_repMatchLenEncoder: rd 8451
rd 4384
rd 17
_isRepG2: rd 12
_dictionarySize: rd 1
_numLiteralPosStateBits:rd 1
_distTableSize: rd 1
_optimumEndIndex: rd 1
state.State: rb 1
state.Prev1IsChar: rb 1
state.Prev2: rb 2
state.PosPrev2: rd 1
state.BackPrev2: rd 1
state.Price: rd 1
state.PosPrev: rd 1
state.BackPrev: rd 1
state.Backs: rd 4
rd 40950
_alignPrices: rd 16
_isRep: rd 12
_posAlignEncoder: rd 256
i_01: rd 1
_state: rb 1
_cache: rb 1
_state.Prev2: rb 2
_posEncoders: rd 1
_numPrevBits: rd 1
_numPosBits: rd 1
_posMask: rd 1
_posStateBits: rd 1
_range: rd 1
_cacheSize: rd 1
_cyclicBufferSize: rd 1
low: rd 2
Models: rd 512
_matchMaxLen: rd 1
pack_pos: rd 1
_cutValue: rd 1
_hash: rd 1
crc_table: rd 256
_buffer: rd 1
_pos: rd 1
_streamPos: rd 1
pack_length: rd 1
;=====================================================================
section '.idata' import data readable writeable
;=====================================================================
dd 0,0,0, RVA kernel_txt, RVA kernel_iat
dd 0,0,0, 0, 0
kernel_iat:
GetCommandLineA dd RVA _GetCommandLineA
CreateFileA dd RVA _CreateFileA
GetFileSize dd RVA _GetFileSize
ReadFile dd RVA _ReadFile
WriteFile dd RVA _WriteFile
CloseHandle dd RVA _CloseHandle
VirtualAlloc dd RVA _VirtualAlloc
VirtualFree dd RVA _VirtualFree
ExitProcess dd RVA _ExitProcess
dd 0
kernel_txt db 'KERNEL32.DLL', 0
align 2
_GetCommandLineA dw 0
db 'GetCommandLineA', 0
_CreateFileA dw 0
db 'CreateFileA', 0
_GetFileSize dw 0
db 'GetFileSize', 0
_ReadFile dw 0
db 'ReadFile', 0
_WriteFile dw 0
db 'WriteFile', 0
_CloseHandle dw 0
db 'CloseHandle', 0
_VirtualAlloc dw 0
db 'VirtualAlloc', 0
_VirtualFree dw 0
db 'VirtualFree', 0
_ExitProcess dw 0
db 'ExitProcess', 0
+1 -1
View File
@@ -1,5 +1,5 @@
[rbmenu]
Диспетчер процессов=cpu
Диспетчер задач=taskman
Управление темой=skincfg
Настройка фона=/sys/media/palitra
Настройка устройств=setup
@@ -55,17 +55,18 @@ int program_console(int pid) {
break;
case SHELL_PUTS:
printf("%s", &buffer->data );
buffer->return_value.written_bytes = printf("%s", &buffer->data );
buffer->cmd = SHELL_OK;
break;
case SHELL_GETC:
buffer->data[0] = (char) getch() ;
*((int *)buffer->data) = getch();
buffer->cmd = SHELL_OK;
break;
case SHELL_GETS:
gets(buffer->data, size - 2);
buffer->return_value.str = gets(buffer->data, size - 2);
buffer->return_value.written_bytes = strlen(buffer->data);
buffer->cmd = SHELL_OK;
break;
+25 -10
View File
@@ -104,10 +104,26 @@ applyKeymap:
cmp al, 9
jnc @f
push eax
push esi edi
shl eax,7
lea eax,[eax*2+eax]
mov [point],eax
mcall 70,get_key
lea edi,[eax*2+eax] ; offset of the layout = index*384
cmp [keymap_file],0
jnz .loaded
mcall 68,27,keymap_path
test eax,eax
jz .fail
mov [keymap_file],eax
mov [keymap_size],edx
.loaded:
lea eax,[edi+384]
cmp eax,[keymap_size]
ja .fail
mov esi,[keymap_file]
add esi,edi
mov edi,current_keymap
mov ecx,384/4
rep movsd
pop edi esi
mcall 21,2,1,current_keymap
inc ecx
mcall 21,,,current_keymap_shift
@@ -118,6 +134,9 @@ applyKeymap:
mcall 21,,9
@@:
ret
.fail:
pop edi esi eax
ret
;---------------------------------------------------------------
align 4
current_keymap rb 128
@@ -132,13 +151,9 @@ point2 dd 0
dd inicont
db '/sys/settings/lang.ini',0
get_key:
dd 0
point dd 0
dd 0
dd 384
dd current_keymap
db '/sys/settings/keymap.key',0
keymap_path db '/sys/settings/keymap.key',0
keymap_file dd 0
keymap_size dd 0
key_r db 0
key_r2 db 0
+3
View File
@@ -1,3 +1,6 @@
-- @taskbar loads keymap.key with f68.27, which unpacks kpack'ed files.
tup.rule("KEYMAP.KEY", "cp %f %o" .. tup.getconfig("KPACK_CMD"), "keymap.key.kpack")
if tup.getconfig("NO_FASM") ~= "" then return end
HELPERDIR = (tup.getconfig("HELPERDIR") == "") and "../.." or tup.getconfig("HELPERDIR")
tup.include(HELPERDIR .. "/use_fasm.lua")
+42
View File
@@ -0,0 +1,42 @@
## TASKMAN - Task Manager
Replaces CPU and SYSMON. Starts from the menu, the system panel or by
`Ctrl+Alt+Del`.
* **Processes** - threads with their CPU and memory. `Details` opens
TINFO, `End` ends the thread, `Run...` starts a program. System threads
(OS, @...) are shown with `System`.
* **Performance** - CPU, temperature, memory and network: the values on
the left, the history as a graph on the right. Temperature comes from
the CPU sensor (Intel, AMD, Hygon, VIA, Zhaoxin) or else from a board
monitoring chip (Winbond, ITE, ABIT uGuru); without either there is no
temperature graph. `CPUID` starts CPUID.
* **Disks** - partitions with label, size and, for memory disks, the
space used. `Open` shows the disk in Eolite.
* **Drivers** - the drivers the kernel has loaded. `Load...` starts
LOADDRV.
* **Autorun** - the programs of `/sys/settings/autorun.dat`. A program
turned off has `#` before it and is shown pale; `Turn on/off` adds or
removes the `#` in the file.
Lists sort by a click on a column header; a second click reverses the
order.
### Keys
| Key | Action |
|---|---|
| `Tab` | Next tab |
| `Esc` | Close |
| `Up`, `Down`, `PgUp`, `PgDn`, `Home`, `End` | Move in a list |
| `Enter` | Processes: Details; Disks: Open |
| `Del` | Processes: End |
| `Space` | Autorun: turn the program on or off |
| Right click on a row | Processes: Details; Disks: Open |
| Mouse wheel | Scroll a list |
### History
* 2026-10 - First version. Replaces CPU (processes) and SYSMON (system
monitor); adds the disks, drivers and autorun tabs and the CPU
temperature sensors; the board chips come from GMON.
+4
View File
@@ -0,0 +1,4 @@
if tup.getconfig("NO_FASM") ~= "" then return end
lang = (tup.getconfig("LANG") == "") and "en_US" or tup.getconfig("LANG")
tup.rule("taskman.asm", "fasm -dlang=" .. lang .. " %f %o " .. tup.getconfig("KPACK_CMD"), "taskman")
+423
View File
@@ -0,0 +1,423 @@
; Drawing and formatting helpers; they keep all registers unless noted.
macro __mov reg, a, b { ; mcall loads small constants shorter
if (~a eq) & (~b eq)
mpack reg, a, b
else if (~a eq) & (b eq)
movi reg, a
end if
}
; An item of a bar: a button with its color, a checkbox with its state or
; a gap
struct BAR
kind db ?
text dd ? ; the caption
arg dd ? ; -> the color, -> the state as a byte
ends
BAR_END = 0
BAR_BUTTON = 1
BAR_CHECK = 2
BAR_GAP = 3
; ebx = x shl 16 + y, ecx = color, edx -> string in UTF-8
draw_text:
pusha
or ecx, TEXT_UTF8
mcall SF_DRAW_TEXT
popa
ret
; eax -> string; out: eax = width in pixels
text_width:
push ecx esi
mov esi, eax
xor ecx, ecx
.next:
lodsb
test al, al
jz .done
call utf8_more
je .next
add ecx, 8
jmp .next
.done:
xchg eax, ecx
pop esi ecx
ret
; eax -> caption; out: eax = width of the button
button_width:
call text_width
add eax, BTN_PAD*2
ret
; Frame in the border color filled with edx. ebx = x shl 16 + w, ecx = y shl 16 + h
frame_rect:
pusha
push edx
mcall SF_DRAW_RECT, , , [sc.work_graph]
pop edx
add ebx, 1 shl 16 - 2
add ecx, 1 shl 16 - 2
mcall SF_DRAW_RECT
popa
ret
; eax = icon, ebx = x shl 16 + y, edx = the background for its white
draw_icon:
pusha
mov esi, [icons]
test esi, esi
jz .done
imul eax, ICON*ICON*4
add esi, eax
mov edi, icon_buf
mov ecx, ICON*ICON
@@:
lodsd
cmp eax, -1
jne .pixel
mov eax, edx
.pixel:
stosd
loop @b
mov edx, ebx
mcall SF_PUT_IMAGE_EXT, icon_buf, (ICON shl 16) + ICON, , 32, 0, 0
.done:
popa
ret
; eax, edx = colors; out: eax = the one half way between them, edx changed
mix:
and eax, 0xFEFEFE
and edx, 0xFEFEFE
add eax, edx
shr eax, 1
ret
; eax -> caption, edx = id, esi = color
bar_button:
pusha
mov edi, eax
call button_width
call bar_place
dec ebx ; the kernel draws one pixel more
dec ecx
mcall SF_DEFINE_BUTTON
add ebx, BTN_PAD shl 16
mov eax, [sc.work_button_text] ; then bar_text
; The end of the bar items: edi -> caption, eax = color, ebx = x shl 16,
; ecx = y shl 16 of the item
bar_text:
shr ecx, 16
add ecx, (BTN_H - TEXT_H)/2
mov bx, cx
xchg eax, ecx
mov edx, edi
call draw_text
popa
ret
; eax -> caption, edx = id, ebp = checked
bar_checkbox:
pusha
mov edi, eax
call button_width ; the box, PAD, the caption: 2 left
call bar_place
add [bar_left], 2*PAD + CHECK - 2*BTN_PAD ; then more room
or edx, BT_HIDE + BT_NOFRAME
mcall SF_DEFINE_BUTTON
mov bx, CHECK
add ecx, ((BTN_H - CHECK)/2) shl 16
mov cx, CHECK
mov [cb.left_s], ebx ; the box of box_lib, the caption
mov [cb.top_s], ecx ; as the other ones
mov eax, [sc.work_light]
mov [cb.color], eax
mov eax, [sc.work_button] ; the frame and the check
mov [cb.border_color], eax
lea eax, [ebp + ebp] ; checked
mov [cb.flags], eax
push cb
call [check_box_draw2]
add ebx, (CHECK + PAD) shl 16
sub ecx, ((BTN_H - CHECK)/2) shl 16
mov eax, [sc.work_text]
jmp bar_text
; Place in the bottom bar: from the left end, or from the right one for ids
; with bit 3. eax = width, edx = id; out: ebx = x shl 16 + w, ecx = y shl 16 + h
bar_place:
lea ebx, [eax + PAD]
test dl, 8
jnz .right
xchg ebx, [bar_left]
add [bar_left], ebx
jmp @f
.right:
sub [bar_right], ebx
mov ebx, [bar_right]
@@:
shl ebx, 16
mov bx, ax
mov ecx, [bar_y]
shl ecx, 16
mov cx, BTN_H
ret
; The items of a bar from the left, esi -> them; the buttons and the
; checkboxes get the ids from BTN_OWN on. Changes all registers.
bar_draw:
mov edx, BTN_OWN
.item:
mov bl, [esi + BAR.kind]
mov eax, [esi + BAR.text]
mov ecx, [esi + BAR.arg]
add esi, sizeof.BAR
dec bl
js .done
jz .button
dec bl
jz .check
add [bar_left], PAD ; a gap
jmp .item
.done:
ret
.button:
push esi
mov esi, [ecx]
call bar_button
pop esi
inc edx
jmp .item
.check:
movzx ebp, byte [ecx]
call bar_checkbox
inc edx
jmp .item
;-------------------------------------------------------------------------------
; Formatting: write to edi and leave it at the terminating zero.
; eax = number; printed as 8 hex digits
fmt_hex:
pusha
mov ebx, 16
mov esi, 8
jmp fmt_num
; eax = number
fmt_uint:
pusha
mov ebx, 10
xor esi, esi
fmt_num: ; ebx = base, esi = the fewest digits
xor ecx, ecx
@@:
xor edx, edx
div ebx
push edx
inc ecx
test eax, eax
jnz @b
cmp ecx, esi
jb @b
@@:
pop eax
cmp al, 10 ; 0..15 to '0'..'9', 'A'..'F'
sbb al, 0x69
das
stosb
loop @b
mov [edi], cl
mov [esp + PUSHA_EDI], edi
popa
ret
; al = a byte of UTF-8; out: ZF = 1 if it goes on with a character
utf8_more:
push eax
and al, 0xC0
cmp al, 0x80
pop eax
ret
; edx -> string; copies up to (ebx - eax) / 8 characters, TEXT_CHARS at
; most, and keeps edi
fmt_clip:
pusha
mov esi, edx
sub ebx, eax
shr ebx, 3
cmp ebx, TEXT_CHARS
jb @f
mov ebx, TEXT_CHARS
@@:
lodsb
test al, al
jz @f
call utf8_more
je .put
dec ebx
js @f
.put:
stosb
cmp edi, text_buf + TEXT_CHARS*4
jb @b
@@:
mov byte [edi], 0
popa
ret
; esi -> string
fmt_str:
push eax esi
@@:
lodsb
stosb
test al, al
jnz @b
dec edi
pop esi eax
ret
; eax -> string
fmt_unit:
xchg esi, eax
call fmt_str
xchg esi, eax
ret
; eax = KB; printed as "123 KB", "1.5 MB", "12.3 GB" etc.
fmt_size:
pusha
mov ebx, 1024
mov esi, sz_units
jmp fmt_scaled
; eax = bits a second; printed as "500 bit/s", "1.5 Mbit/s" etc.
fmt_rate:
pusha
mov ebx, 1000
mov esi, sz_bits ; then fmt_scaled
; ebx = the step of the units, esi -> the units, each ended with 0: the
; number in the largest one it fills, small ones with a decimal but .0
fmt_scaled:
xor ecx, ecx
xor edx, edx
@@:
cmp eax, ebx
jb @f
xor edx, edx
div ebx
inc ecx
jmp @b
@@:
call fmt_uint
cmp eax, 100
jae .unit
imul eax, edx, 10
xor edx, edx
div ebx
test eax, eax
jz .unit
mov byte [edi], "."
inc edi
call fmt_uint
.unit:
dec ecx
js @f
.skip:
lodsb
test al, al
jnz .skip
jmp .unit
@@:
call fmt_str
mov [esp + PUSHA_EDI], edi
popa
ret
; eax = seconds; printed as "h:mm:ss"
fmt_time:
pusha
xor edx, edx
mov ecx, 3600
div ecx
call fmt_uint
xchg eax, edx
mov cl, 60
div cl
movzx edx, ah
call .two
xchg eax, edx
call .two
mov [esp + PUSHA_EDI], edi
popa
ret
.two: ; eax = 0..99
aam
add ax, "00"
xchg al, ah
shl eax, 8
mov al, ":"
stosd
dec edi
ret
; esi -> path: the program without parameters
run_plain:
xor edx, edx ; then run_app
; esi -> path, edx -> parameters or 0
run_app:
pusha
mov [app_info.Flags], edx
mov [app_info.FileName], esi
mcall SF_FILE, app_info
popa
ret
+188
View File
@@ -0,0 +1,188 @@
; The monitoring chips of older boards, ported from GMON: Winbond W836xx and
; ITE IT87xx at ports 0x295/0x296, ABIT uGuru at 0xE0/0xE4. Their first
; temperature stands in for a CPU without a sensor.
HWM_PORT = 0x295 ; index, data at + 1
SIO_PORT = 0x2E ; Super I/O config, data at + 1
UGURU_CMD = 0xE0
UGURU_DATA = 0xE4
WB_BANK = 0x4E ; the registers of Winbond: the bank,
WB_VENDOR = 0x4F ; the vendor, 0x80 in WB_BANK: its
WB_ID = 0x5CA3 ; high byte
WB_TEMP = 0x50 ; in bank 1
SIO_CHIP_ID = 0x20 ; of the Super I/O, then of ITE
ITE_ID = 0x87 ; the high byte
ITE_TEMP = 0x29
UGURU_TEMP = 0x2100 ; bank, sensor
; The chip of the board: hwm_read; out: eax = it, 0 if none: the ports
; given back
hwm_init:
mcall SF_SET_PORTS, 0, HWM_PORT, HWM_PORT + 1
test eax, eax
jnz .uguru
call wb_probe
je .found
mcall SF_SET_PORTS, 0, SIO_PORT, SIO_PORT + 1
test eax, eax
jnz .uguru
call ite_probe
je .found
.uguru:
mcall SF_SET_PORTS, 0, UGURU_CMD, UGURU_DATA
test eax, eax
jnz .none
in al, UGURU_CMD
test al, al
jz @f
cmp al, 0xAC
jne .none
@@:
in al, UGURU_DATA
test al, al
jz @f
cmp al, 8
jne .none
@@:
mov eax, uguru_read
.found:
mov [hwm_read], eax
ret
.none:
mcall SF_SET_PORTS, 1, HWM_PORT, HWM_PORT + 1
mcall SF_SET_PORTS, 1, UGURU_CMD, UGURU_DATA
xor eax, eax
ret
; al = bank (or 0x80: the high byte of the vendor), ah = register; out: eax
wb_get:
push eax
mov ah, WB_BANK
call hwm_index
pop eax
out dx, al ; then hwm_get
; ah = register; out: eax
hwm_get:
call hwm_index
in al, dx
movzx eax, al
ret
hwm_index: ; out: dx = the data port
mov dx, HWM_PORT
mov al, ah
out dx, al
inc edx
ret
; out: ZF = 1 and eax = the read procedure if found
wb_probe:
mov ax, WB_VENDOR shl 8 ; a byte at a time
call wb_get
xchg ebx, eax
mov ax, WB_VENDOR shl 8 + 0x80
call wb_get
mov bh, al
cmp bx, WB_ID
jne .done
mov eax, wb_read
cmp eax, eax
.done:
ret
; out: ZF = 1 and eax = the read procedure if found
ite_probe:
mov eax, 0x55550187 ; MB PnP mode
mov ecx, 4
@@:
out SIO_PORT, al
shr eax, 8
loop @b
mov al, SIO_CHIP_ID
out SIO_PORT, al
in al, SIO_PORT + 1
xchg eax, esi
mov al, 2 ; leave the mode
out SIO_PORT, al
out SIO_PORT + 1, al
mcall SF_SET_PORTS, 1, SIO_PORT, SIO_PORT + 1
xchg eax, esi
cmp al, ITE_ID
mov eax, ite_read
ret
; out: eax = the first temperature
wb_read:
mov ax, WB_TEMP shl 8 + 1
jmp wb_get
ite_read:
mov ah, ITE_TEMP
jmp hwm_get
uguru_read:
mov ax, UGURU_TEMP ; then uguru_sensor
; ax = sensor; out: eax
uguru_sensor:
push ebx
mov ebx, eax
mov al, ah ; the bank
out UGURU_DATA, al
mov ah, 8
call .wait
mov al, bl
out UGURU_CMD, al
mov ah, 1
call .wait
in al, UGURU_CMD
movzx ebx, al
mov ecx, 1000 ; back to the ready state
.ready:
in al, UGURU_DATA
cmp al, 8
je .done
xor eax, eax
out UGURU_DATA, al
mov ah, 9
call .wait
loop .ready
.done:
xchg eax, ebx
pop ebx
ret
.wait: ; for ah at the data port
push ecx
mov ecx, 1000
@@:
in al, UGURU_DATA
cmp al, ah
loopne @b
pop ecx
ret
hwm_read dd nothing ; the procedure of the chip
uglobal
align 4
hwm_temp dd ? ; degrees
endg
+684
View File
@@ -0,0 +1,684 @@
; List of a tab: rows in columns with a header, a selected row and a scrollbar on
; the panel. The columns go from the left, one of them, width 0, takes what
; the others leave. A click on a row selects it, then calls the trigger of
; that button; a key of the hotkeys calls its trigger. `list` is the list of
; the open tab; a closed tab keeps it in its descriptor.
struct LIST
cols dd ? ; the columns
cols_end dd ?
sort dd ? ; the sorted column
left dd ? ; the triggers: a left click,
right dd ? ; a right click,
keys dd ? ; -> HOTKEYs, ended by 0
dim dd ? ; a byte in the row: not 0, it is pale; 0: none
count dd ?
sel dd ?
first dd ?
key dd ? ; the first dword of the selected row
desc dd ? ; 1: the sorted column goes down
view dd ? ; -> the pointers to the rows
ends
struct HOTKEY
key db ?
trigger dw ?
ends
struct COL
caption dd ?
field db ? ; offset in the row
kind db ?
width db ? ; 0: what the others leave
ends
; The list: the header, the rows and the scrollbar.
list_draw:
mov ebx, [area_w] ; what the others leave to the widest
sub ebx, 1 + SB_W
mov esi, [list.cols]
@@:
movzx edx, byte [esi + COL.width]
sub ebx, edx
add esi, sizeof.COL
cmp esi, [list.cols_end]
jb @b
mov [col_rest], ebx
mov eax, [area_h] ; the rows that fit
sub eax, 2 + HDR_H + 1
xor edx, edx
mov ecx, ROW_H
div ecx
mov [rows], eax
mov ebx, PAD shl 16 ; the header and the line under it,
mov bx, word [area_w] ; left of the scrollbar
sub bx, SB_W - 1
mov ecx, (AREA_Y shl 16) + HDR_H + 2
mov edx, [mid]
call frame_rect
xor eax, eax
mov ebp, AREA_Y + 1 + (HDR_H - TEXT_H)/2
call list_line ; then list_rows
; The rows and the scrollbar only, for new data.
list_rows:
call list_clamp
mov edi, [list.first]
mov ecx, ((AREA_Y + HDR_H + 2) shl 16) + ROW_H
mov ebp, [rows]
.row:
mov ebx, (PAD + 1) shl 16
mov bx, word [area_w]
sub bx, 1 + SB_W
mov edx, [sc.work_light]
mov esi, [sc.work_text]
cmp edi, [list.sel]
jne @f
cmp edi, [list.count] ; a row there
jae @f
mov edx, [sc.work_button]
mov esi, [sc.work_button_text]
@@:
mcall SF_DRAW_RECT
cmp edi, [list.count]
jae @f
pusha
mov eax, [list.view]
mov eax, [eax + edi*4]
mov ebp, ecx
shr ebp, 16
add ebp, (ROW_H - TEXT_H)/2
mov ecx, esi
mov esi, [list.dim] ; pale: half way to the background
test esi, esi
jz .line
cmp byte [eax + esi], 0
je .line
xchg eax, ecx
call mix
xchg eax, ecx
.line:
call list_line
popa
@@:
add ecx, ROW_H shl 16
inc edi
dec ebp
jg .row ; then sb_draw
; The scrollbar of box_lib at the right of the list, as high as it
sb_draw:
call sb_set
push sb
call [scrollbar_v_draw]
ret
; One line of the list at y = ebp: the captions if eax = 0, lines between
; them, the sorted one with an arrow, otherwise the cells of row eax in color
; ecx on background edx. Left or right as col_left says.
list_line:
pusha
mov ebx, PAD + 1 ; the left of the column
mov esi, [list.cols]
.col:
pusha
movzx edx, byte [esi + COL.field]
add edx, eax
test eax, eax
jnz .cell
mov edx, [esi + COL.caption]
mov ecx, [sc.work_text]
jmp .draw
.cell:
call cell_text
.draw:
call col_width ; the text in the cell
lea eax, [ebx + eax - CELL_PAD]
xchg eax, ebx
add eax, CELL_PAD
mov edi, text_buf
call fmt_clip
mov edx, edi
call col_left
jc @f
mov eax, edx
call text_width
neg eax
add eax, ebx
@@:
shl eax, 16
mov ax, bp
xchg eax, ebx
call draw_text
cmp dword [esp + PUSHA_EAX], 0 ; the captions
jne .picture
cmp esi, [list.cols] ; a line left of the column, but the
je @f ; first one at the frame
push ebx
mov ebx, [esp + 4 + PUSHA_EBX] ; the left
shl ebx, 16
inc ebx
mov ecx, ((AREA_Y + 1) shl 16) + HDR_H
mcall SF_DRAW_RECT, , , [sc.work_graph]
pop ebx
@@:
cmp esi, [list.sort]
jne .next
mov edi, [list.desc]
sub ebx, 5 shl 16 ; 2 pixels before the caption on the
call col_left ; right, after the one on the left
jnc @f
mov eax, text_buf
call text_width
add eax, 11
shl eax, 16
add ebx, eax
@@:
call draw_arrow
jmp .next
.picture: ; a bar or an icon in a row
movzx edx, byte [esi + COL.field]
add edx, [esp + PUSHA_EAX] ; the row
mov edx, [edx]
call col_width
cmp byte [esi + COL.kind], KIND_BAR
jb .next
ja .icon
mov ebx, [esp + PUSHA_EBX] ; the bar across the cell
add ebx, CELL_PAD
shl ebx, 16
sub eax, 2*CELL_PAD
mov bx, ax
movzx ecx, bp
shl ecx, 16
mov cx, TEXT_H
xchg eax, edx
mov edx, [sc.work_light]
call frame_rect
cmp eax, -1
je .next
add ebx, 2 shl 16 - 4 ; a light line around it, from the
add ecx, 2 shl 16 - 4 ; selected row too
movzx edx, bx
mul edx
shr eax, 10
mov bx, ax
mcall SF_DRAW_RECT, , , [sc.work_button] ; as the graphs
jmp .next
.icon:
sub eax, ICON ; in the middle of the cell
shr eax, 1
add eax, [esp + PUSHA_EBX]
shl eax, 16
lea ecx, [ebp - (ICON - TEXT_H)/2]
mov ax, cx
xchg eax, ebx
xchg eax, edx
mov edx, [esp + PUSHA_SIZE + PUSHA_EDX] ; of the first one:
; the background
call draw_icon
.next:
call col_width ; the next column after this one
add [esp + PUSHA_EBX], eax ; its left
popa
add esi, sizeof.COL
cmp esi, [list.cols_end]
jb .col
popa
ret
; esi -> column, edx -> its field in the row; out: edx -> the text of the
; cell, "" for a bar or an icon
cell_text:
cmp byte [esi + COL.kind], KIND_STR
jb .done
mov edx, [edx]
je .done
mov eax, edx
mov edi, text_buf
mov edx, edi
mov byte [edi], 0 ; -1: unknown, nothing to show
cmp eax, -1
je .done
cmp byte [esi + COL.kind], KIND_SIZE
jb .uint
ja .hex
jmp fmt_size
.hex:
cmp byte [esi + COL.kind], KIND_HEX ; a bar or an icon: drawn below
jne .done
jmp fmt_hex
.uint:
call fmt_uint
cmp byte [esi + COL.kind], KIND_PCT
jne .done
mov word [edi], "%"
.done:
ret
; esi -> column; out: CF = 1 if its caption and text go left: text and the
; widest column, but the bar
col_left:
cmp byte [esi + COL.kind], KIND_NUM ; text: CF = 1
jb .done
cmp byte [esi + COL.kind], KIND_BAR ; the bar and icons: CF = 0
jae .done
cmp byte [esi + COL.width], 1 ; the widest: CF = 1
.done:
ret
; esi -> column; out: eax = its width
col_width:
movzx eax, byte [esi + COL.width]
test eax, eax
jnz @f
mov eax, [col_rest]
@@:
ret
; The end of a scan: ebp -> the end of the view.
list_done:
sub ebp, [list.view]
shr ebp, 2
mov [list.count], ebp ; then list_sort
; Sort the view by the sorted column and find the selected row again.
list_sort:
mov ebp, [list.view]
mov ecx, 1 ; insertion sort, stable
.outer:
cmp ecx, [list.count]
jae .select
mov esi, [ebp + ecx*4]
mov ebx, ecx
.inner:
mov edi, [ebp + ebx*4 - 4]
call list_less
jnc .put
mov [ebp + ebx*4], edi
dec ebx
jnz .inner
.put:
mov [ebp + ebx*4], esi
inc ecx
jmp .outer
.select:
mov ecx, [list.count]
mov eax, [list.key]
@@:
dec ecx
js @f
mov esi, [ebp + ecx*4]
cmp [esi], eax
jne @b
mov [list.sel], ecx
@@:
ret
; esi, edi -> rows; out: CF = 1 if esi goes before edi
list_less:
pusha
mov ebx, [list.sort]
movzx ecx, byte [ebx + COL.field]
add esi, ecx
add edi, ecx
cmp [list.desc], 0
je @f
xchg esi, edi
@@:
cmp byte [ebx + COL.kind], KIND_STR
ja .num
jb @f
mov esi, [esi] ; the text by its pointer
mov edi, [edi]
@@:
lodsb ; the letters of either case alike
mov ah, [edi]
inc edi
mov dl, al
or ax, 0x2020
cmp al, ah
jne @f
test dl, dl
jz @f
cmp byte [edi - 1], 0 ; the end of edi, not a blank
jne @b
@@:
popa
ret
.num: ; -1, unknown, before 0
mov eax, [esi]
inc eax
mov edx, [edi]
inc edx
cmp eax, edx
popa
ret
; An arrow up, or down if edi = 1: a triangle of 4 lines, line i of 2*i + 1
; pixels, its tip at x = ebx shr 16, around the middle of the capitals of
; text at y = bx.
draw_arrow:
pusha
lea ecx, [edi*2 + edi + TEXT_H/2 - 2] ; from the top if it
add cx, bx ; goes up, else from the bottom
shl ecx, 16
inc ecx
shl edi, 17 ; the next line: 1 down or up
neg edi
add edi, 1 shl 16
mov bx, 1
mov esi, 4
@@:
mcall SF_DRAW_RECT, , , [sc.work_text]
add ebx, (-1 shl 16) + 2
add ecx, edi
dec esi
jnz @b
popa
ret
; eax = rows the wheel moves, esi = mouse buttons: box_lib moves the list,
; again while held; out: ebp = list.first before, drawn again if it changes
scroll_mouse:
mov ebp, [list.first]
add [list.first], eax
call sb_set
xor eax, eax
mov edi, [rows] ; all rows seen: no thumb to drag
cmp edi, [list.count]
jae @f
push sb
call [scrollbar_v_mouse]
mov eax, [sb.position]
xchg eax, [list.first]
sub eax, [list.first] ; moved while held: again after 10
jz @f ; waits of the main loop if pressed
mov eax, esi ; now, else after 2
and eax, MB_LEFT
jz @f
mov al, 2
test esi, MB_LEFT_DOWN
jz @f
mov al, 10
@@:
mov [repeat_at], eax
ret
sb_set: ; the list state to it
mov eax, [area_w]
add eax, PAD - SB_W
mov [sb.x_pos], ax
mov eax, [area_h]
mov [sb.y_size], ax
mov [sb.all_redraw], 1
mov edi, sb.max_area
mov eax, [list.count]
stosd
mov eax, [rows]
stosd
mov eax, [list.first]
stosd
mov eax, [sc.work_dark]
stosd
mov eax, [mid]
stosd
mov eax, [sc.work_graph]
stosd
ret
; Keep sel and first in range and remember the selected row.
list_clamp:
pusha
mov ecx, [list.count]
mov edi, list.sel
call clamp
jecxz @f
mov edx, [list.view]
mov eax, [edx + eax*4]
mov eax, [eax]
mov [list.key], eax
@@:
popa
pusha ; first in range
mov ecx, [list.count]
sub ecx, [rows]
inc ecx
mov edi, list.first
call clamp
popa
ret
clamp: ; [edi] into [0, ecx - 1]
mov eax, [edi]
cmp eax, ecx
jl @f
lea eax, [ecx - 1]
@@:
test eax, eax
jns @f
xor eax, eax
@@:
stosd
ret
list_key: ; al = key
mov esi, [list.keys]
.hotkey:
mov ah, [esi + HOTKEY.key]
test ah, ah
jz .move
add esi, sizeof.HOTKEY
cmp ah, al
jne .hotkey
movzx eax, [esi - sizeof.HOTKEY + HOTKEY.trigger]
jmp eax
.move:
sub al, KEY_DOWN
cmp al, KEY_PGUP - KEY_DOWN
ja .done
movzx eax, al
movsx edx, byte [.moves + eax*2 + 1]
imul edx, [rows]
movsx eax, byte [.moves + eax*2]
add edx, eax
add [list.sel], edx
call list_clamp
mov ebx, [list.sel] ; scroll to the selection
mov ecx, [rows]
sub ebx, ecx
inc ebx
sub [list.first], ebx
mov edi, list.first
call clamp
add [list.first], ebx
jmp list_rows
.done:
ret
; rows, pages for the keys KEY_DOWN..KEY_PGUP: down, up, right, home, end,
; del, pgdn, pgup
.moves db 1, 0, -1, 0, 0, 0, 0, -128, 0, 127, 0, 0, 0, 1, 0, -1
; Wheel scrolls; left button selects a row, sorts by a column or moves the
; scrollbar; right click opens the row.
list_mouse:
call get_mouse
imul eax, 3
call scroll_mouse ; every event: it follows a drag
test esi, MB_LEFT + MB_RIGHT_DOWN
jz .moved
sub ebx, PAD ; inside the list, left of the
jle .moved ; scrollbar
mov eax, [area_w]
sub eax, SB_W
cmp ebx, eax
jge .moved
sub ecx, AREA_Y + HDR_H + 2
jl .header
test esi, MB_LEFT_DOWN + MB_RIGHT_DOWN ; a row: not dragged to
jz .moved
xchg eax, ecx
xor edx, edx
mov ecx, ROW_H
div ecx
cmp eax, [rows]
jae .moved
add eax, [list.first]
cmp eax, [list.count]
jae .moved
mov [list.sel], eax
shr esi, 9 ; MB_RIGHT_DOWN: 0 left, 1 right
and esi, 1
push [list.left + esi*4] ; the selection drawn, then list_rows
jmp list_rows ; returns to the trigger
.moved: ; a drag of the thumb keeps its pixels
cmp ebp, [list.first]
jne list_rows
ret
.header:
cmp ecx, -(HDR_H + 1)
jl .moved
test esi, MB_LEFT_DOWN
jz .moved
mov esi, [list.cols] ; the column under the cursor
dec ebx
.col:
call col_width
sub ebx, eax
jl .sort
add esi, sizeof.COL
cmp esi, [list.cols_end]
jb .col
ret
.sort: ; again: the other way, else its own
xor eax, eax
cmp byte [esi + COL.kind], KIND_PCT
setae al
cmp esi, [list.sort]
jne .order
mov eax, [list.desc]
xor al, 1
.order:
mov [list.desc], eax
mov [list.sort], esi
call list_sort
jmp list_draw
; out: esi = mouse buttons held, in bits 8.. the ones pressed, not held at
; the last event, and the mouse not moved since; ebx, ecx = x, y in the
; client area; eax = the wheel
get_mouse:
mcall SF_MOUSE_GET, SSF_BUTTON_EXT
mov esi, eax
movzx eax, al
xchg al, byte [buttons]
shl eax, 8
not eax
and esi, eax
mcall SF_MOUSE_GET, SSF_WINDOW_POSITION
movsx ecx, ax ; in the client area
sar eax, 16
xchg edx, eax
mcall SF_MOUSE_GET, SSF_SCROLL_DATA
mov ebx, edx
movsx eax, ax ; the wheel
ret
no_keys db 0 ; HOTKEYs of a list without them
uglobal
align 4
list LIST
rows dd ? ; that fit the panel
col_rest dd ? ; the width of the widest column
repeat_at dd ? ; waits till a held arrow repeats
endg
+94
View File
@@ -0,0 +1,94 @@
; Strings in UTF-8; the caption starts with its encoding byte.
if lang eq ru_RU
sz_title db 3, "Диспетчер задач", 0
sz_tab_procs db "Процессы", 0
sz_tab_perf db "Нагрузка", 0
sz_tab_disks db "Диски", 0
sz_col_free db "Свободно", 0
sz_run db "Запустить...", 0
sz_kill db "Завершить", 0
sz_shutdown db "Завершение работы...", 0
sz_info db "Детали", 0
sz_system db "Системные", 0
sz_col_name db "Имя", 0
sz_col_cpu db "ЦП", 0
sz_col_mem db "Память", 0
sz_freq db "Частота", 0
sz_mhz db " МГц", 0
sz_uptime db "Время работы", 0
sz_threads db "Потоки", 0
sz_used db "Занято", 0
sz_total db "Всего", 0
sz_temp db "Температура", 0
sz_net db "Сеть", 0
sz_received db "Принято", 0
sz_sent db "Отправлено", 0
sz_crit db "Критическая", 0
sz_units db " КБ", 0, " МБ", 0, " ГБ", 0, " ТБ", 0
sz_bits db " бит/с", 0, " Кбит/с", 0, " Мбит/с", 0, " Гбит/с", 0
else if lang eq es_ES
sz_title db 3, "Gestor de tareas", 0
sz_tab_procs db "Procesos", 0
sz_tab_perf db "Recursos", 0
sz_tab_disks db "Discos", 0
sz_col_free db "Libre", 0
sz_run db "Ejecutar...", 0
sz_kill db "Finalizar", 0
sz_shutdown db "Apagar el sistema...", 0
sz_info db "Detalles", 0
sz_system db "Sistema", 0
sz_col_name db "Nombre", 0
sz_col_cpu db "CPU", 0
sz_col_mem db "Memoria", 0
sz_freq db "Frecuencia", 0
sz_uptime db "Activo", 0
sz_threads db "Hilos", 0
sz_used db "En uso", 0
sz_total db "Total", 0
sz_temp db "Temperatura", 0
sz_net db "Red", 0
sz_received db "Recibido", 0
sz_sent db "Enviado", 0
sz_crit db "Crítica", 0
else
sz_title db 3, "Task Manager", 0
sz_tab_procs db "Processes", 0
sz_tab_perf db "Performance", 0
sz_tab_disks db "Disks", 0
sz_col_free db "Free", 0
sz_run db "Run...", 0
sz_kill db "End", 0
sz_shutdown db "Shut down...", 0
sz_info db "Details", 0
sz_system db "System", 0
sz_col_name db "Name", 0
sz_col_cpu db "CPU", 0
sz_col_mem db "Memory", 0
sz_freq db "Frequency", 0
sz_uptime db "Uptime", 0
sz_threads db "Threads", 0
sz_used db "Used", 0
sz_total db "Total", 0
sz_temp db "Temperature", 0
sz_net db "Network", 0
sz_received db "Received", 0
sz_sent db "Sent", 0
sz_crit db "Critical", 0
end if
if ~ lang eq ru_RU
sz_mhz db " MHz", 0
sz_units db " KB", 0, " MB", 0, " GB", 0, " TB", 0
sz_bits db " bit/s", 0, " kbit/s", 0, " Mbit/s", 0, " Gbit/s", 0
end if
sz_col_id db "ID", 0
if lang eq ru_RU | lang eq es_ES
sz_col_num db "Nº", 0
else
sz_col_num db " #", 0
end if
sz_deg db " °C", 0
sz_pct db "%", 0
+386
View File
@@ -0,0 +1,386 @@
; Temperature on the Performance tab: the sensor of the CPU (Intel from
; Core, AMD from K8, Hygon, VIA C7, Nano and Zhaoxin; the rules are those
; of Linux coretemp, k8temp, k10temp and via-cputemp), else the first one
; of a monitoring chip of the board (hwmon.inc).
MSR_THERM_STATUS = 0x19C ; Intel: the core, the package,
MSR_PKG_THERM = 0x1B1 ; TjMax in bits 16-23
MSR_TEMP_TARGET = 0x1A2
MSR_VIA_TEMP = 0x1423 ; Nano and Zhaoxin, C7
MSR_C7_TEMP = 0x1169
AMD_NB = 0xC300 ; PCI 00:18.3, then its registers:
K8_THERMTRIP = 0xC3E4 ; K8, the others to Family 16h
NB_TEMP = 0xC3A4
VENDOR_AMD = 0x1022
VENDOR_HYGON = 0x1D94
SMN_ZEN_TEMP = 0x59800 ; the address, the index register
SMN_ZEN_INDEX = 0x60 ; on the root complex, 00:00.0
SMN_F15_TEMP = 0xD8200CA4 ; Family 15h from model 60h
SMN_F15_INDEX = 0xB8
; The sensor of the CPU, else the chip; the temperature graph if any.
sensors_init:
pusha
call cpu_sensor
cmp [cpu_temp], chip_temp
je .chip
mcall SF_THREAD_CONTROL, SSF_CREATE_THREAD, msr_probe, probe_stack_top
mov esi, 20 ; up to 0.2 s
@@:
cmp [probe], 2
je @f
mcall SF_SLEEP, 1
dec esi
jnz @b
@@:
cmp [probe], 0
jne @f
mov [cpu_temp], chip_temp ; the kernel killed the probe
@@:
cmp [tjmax], 0
jne .chip
mov byte [tjmax], 100
.chip:
cmp [cpu_temp], chip_temp ; the chip for a CPU without a sensor
jne .temp
call hwm_init
test eax, eax
jz @f
.temp:
inc [temp_on] ; a graph for any sensor
@@:
cmp [cpu_temp], intel_temp ; TjMax of Intel only
je @f
mov [temp_graph.info], no_info
@@:
popa
ret
; cpu_temp and what it reads, by the vendor and the model
cpu_sensor:
pushfd ; CPUID if the ID flag can be changed
pop eax
xor eax, 1 shl 21
push eax
popfd
pushfd
pop ecx
cmp eax, ecx
jne .done
xor eax, eax
cpuid
mov esi, eax ; the last leaf
mov edi, ebx ; vendor
mov eax, 1
cpuid
mov ebp, eax ; signature
movzx ecx, ah
and cl, 0xF ; family
movzx edx, al
shr edx, 4 ; model
cmp cl, 6
jb @f
shr eax, 12
and al, 0xF0
or dl, al
cmp cl, 0xF
jne @f
movzx eax, ah
add ecx, eax
@@:
cmp edi, "Genu"
je intel_sensor
cmp edi, " Sh" ; C7, Nano and Zhaoxin, the probe
je via_sensor ; drops the others
cmp edi, "Cent"
je via_sensor
cmp edi, "Auth"
je amd_sensor
cmp edi, "Hygo"
je amd_sensor
.done:
ret
; ecx = family, edx = model, esi = the last leaf of CPUID, ebp = signature
intel_sensor:
cmp esi, 6
jb .done
push ecx edx
mov eax, 6
cpuid
pop edx ecx
test al, 1 ; digital thermal sensor
jz .done
mov [cpu_temp], intel_temp
test al, 1 shl 6 ; the package one
jz @f
mov [therm_msr], MSR_PKG_THERM
mov [therm_valid], 1 shl 31 ; it has no "reading valid" bit
@@:
cmp ecx, 6 ; TjMax: 100 before Nehalem,
jne .done ; then from the CPU but on Atoms
cmp edx, 0x1A
jb .done
mov esi, .atoms
@@:
lodsw
test al, al
jz @f ; 0: msr_probe reads it
cmp al, dl
jne @b
@@:
mov byte [tjmax], ah
cmp dl, 0x1C ; Pineview: stepping 10
jne .done
and ebp, 0xF
cmp ebp, 10
jne .done
mov byte [tjmax], 100
.done:
ret
; TjMax of Atoms without MSR_TEMPERATURE_TARGET, and Xeon 7400
.atoms db 0x1C, 90, 0x1D, 100, 0x26, 90, 0x27, 90, 0x35, 90, 0x36, 100, 0, 0
; ecx = family, edx = model
via_sensor:
mov eax, MSR_VIA_TEMP
cmp ecx, 6
ja @f
cmp dl, 0xF
jae @f
mov ax, MSR_C7_TEMP
@@:
mov [therm_msr], eax
mov [cpu_temp], via_temp
ret
; ecx = family, edx = model
amd_sensor:
cmp ecx, 0xF
jb .done
ja .k10
push edx ; K8 with a thermal sensor
mov eax, 0x80000007
cpuid
test dl, 1
pop edx
jz .done
cmp dl, 0x69 ; revision G desktops read lower
jb @f
xchg eax, edx
mov edi, .k8_mobile
mov ecx, 3
repne scasb
je @f
mov [k8_zero], 49 - 21
@@:
mov esi, k8_temp
jmp .nb
.k10:
mov eax, SMN_ZEN_TEMP ; Zen
mov [smn_index], SMN_ZEN_INDEX
cmp ecx, 0x17
jae .smn
mov eax, SMN_F15_TEMP
mov [smn_index], SMN_F15_INDEX
cmp ecx, 0x15
jne @f
cmp edx, 0x60
jae .smn
@@:
cmp ecx, 0x16
ja .done
mov esi, amd_nb_temp
.nb:
mov ecx, AMD_NB
jmp .pci
.smn:
mov [smn_addr], eax
xor ecx, ecx
mov esi, amd_smn_temp
.pci: ; esi = the procedure, if the
call pci_read ; device is AMD or Hygon
cmp ax, VENDOR_AMD
je @f
cmp ax, VENDOR_HYGON
jne .done
@@:
mov [cpu_temp], esi
.done:
ret
.k8_mobile db 0x6C, 0x7C, 0xC1
; ecx = device shl 8 + register on bus 0; out: eax
pci_read: ; the callers keep ebx
mcall SF_PCI, SSF_READ_DWORD
ret
; out: eax = temperature of the CPU, CF = 1 if unknown
via_temp:
call read_therm
and eax, 0xFFFFFF
ret
; out: eax = the low dword of [therm_msr]
read_therm:
mcall SF_SYS_MISC, SSF_READ_MSR, , [therm_msr]
ret
intel_temp:
call read_therm
or eax, [therm_valid] ; the reading is valid
jns no_temp
shr eax, 16
and eax, 0x7F
neg eax
add eax, [tjmax]
clc
ret
k8_temp:
mov ecx, K8_THERMTRIP
call pci_read
shr eax, 16
movzx eax, al
sub eax, [k8_zero]
clc
ret
amd_smn_temp:
mcall SF_PCI, SSF_WRITE_DWORD, [smn_index], [smn_addr]
add ecx, 4 ; the data after the index
call pci_read
test eax, 1 shl 19 ; the range is -49..206
jz amd_temp
or eax, 3 shl 16
jmp amd_temp
amd_nb_temp:
mov ecx, NB_TEMP
call pci_read ; then amd_temp
; eax = the reported temperature of AMD
amd_temp:
mov edx, eax
shr eax, 24 ; 1/8 of a degree from bit 21
and edx, 3 shl 16
cmp edx, 3 shl 16
jne @f
sub eax, 49
@@:
clc
ret
chip_temp: ; none in the CPU: the first of the chip
mov eax, [hwm_temp]
jmp @b
no_temp:
stc
ret
; A thread reads the MSRs first: if one is not there, the kernel kills
; the thread, not the program.
msr_probe:
call [cpu_temp]
inc [probe]
cmp [tjmax], 0
jne @f
mcall SF_SYS_MISC, SSF_READ_MSR, , MSR_TEMP_TARGET
shr eax, 16
test al, al ; 0 in some virtual machines
jz @f
mov byte [tjmax], al
@@:
inc [probe]
mcall SF_TERMINATE_PROCESS
; Once a second: the sensors and the temperature for the graph
sensors_read:
pusha
xor eax, eax
call [hwm_read]
cmp eax, 127 ; 127 and more: no sensor
jb @f
xor eax, eax
@@:
mov [hwm_temp], eax
call [cpu_temp]
jnc .got
mov eax, [last_temp] ; not valid this time
.got:
mov [last_temp], eax
mov edi, last_temp ; not below 0
mov ecx, 1000
call clamp
mov ecx, [hist_pos]
mov [hist_temp + ecx*4], eax
popa
ret
; An ITEM of temp_info
get_tjmax:
mov eax, [tjmax]
call fmt_uint ; then deg_unit
deg_unit:
mov eax, sz_deg
jmp fmt_unit
cpu_temp dd chip_temp ; the procedure
therm_msr dd MSR_THERM_STATUS
therm_valid dd 0
tjmax dd 100
k8_zero dd 49
uglobal
align 4
temp_on dd ? ; a graph of the temperature
smn_addr dd ?
smn_index dd ?
last_temp dd ?
probe dd ? ; 1: the sensor is read, 2: done
rb 256
probe_stack_top:
hist_temp rd HIST_LEN
endg
+111
View File
@@ -0,0 +1,111 @@
; Statistics shared by the tabs, once a second: the threads, their CPU and
; memory, the history of the graphs.
struct PROC ; an item of `procs`
pid dd ?
cpu dd ? ; cycles / 256, then percent
mem dd ? ; KB
name rb 12 ; zero padded
ends
struct RAM_INFO ; function 18.20
total dd ? ; pages
free dd ?
page_faults dd ?
heap_size dd ? ; the kernel heap, bytes
heap_free dd ?
heap_blocks dd ?
heap_free_blocks dd ?
heap_max_free dd ?
heap_max_used dd ?
ends
; The threads, their CPU and memory, the history of the graphs.
sample:
pusha
mov edi, procs
xor edx, edx ; cycles of all threads / 256
xor ecx, ecx
.slot:
inc ecx
mcall SF_THREAD_INFO, pinfo
mov ebp, eax ; the last slot
cmp [pinfo.slot_state], TSTATE_FREE
je .next
mov eax, [ebx + process_information.PID]
stosd ; PROC.pid
mov eax, [ebx + process_information.cpu_usage]
shr eax, 8 ; the sum fits 32 bits
stosd ; PROC.cpu
add edx, eax
mov eax, [ebx + process_information.used_memory]
inc eax
shr eax, 10
stosd ; PROC.mem
lea esi, [ebx + process_information.process_name]
movsd ; PROC.name: 11 bytes and 0
movsd
movsd
mov byte [edi - 1], 0
cmp edi, procs + MAX_PROCS * sizeof.PROC
jae .done
.next:
cmp ecx, ebp
jb .slot
.done:
mov [procs_end], edi
; Percent of CPU = cycles of the thread / 1% of cycles of all threads.
xchg eax, edx
cdq
mov ecx, 100
div ecx
inc eax
xchg eax, ecx
mov esi, procs
@@:
mov eax, [esi + PROC.cpu]
cdq
div ecx
mov [esi + PROC.cpu], eax
add esi, sizeof.PROC
cmp esi, edi
jb @b
inc [hist_pos] ; the place of this sample
and [hist_pos], HIST_LEN - 1
mcall SF_SYSTEM, SSF_GET_RAM_INFO, ram_info
mov eax, [ram_info.total]
sub eax, [ram_info.free]
imul eax, 100
cdq
div [ram_info.total]
call sensors_read
call net_sample
mov ecx, [hist_pos]
mov [hist_mem + ecx*4], eax
mov eax, 100
sub eax, dword [procs + PROC.cpu] ; the first thread is IDLE
mov [hist_cpu + ecx*4], eax
popa
ret
uglobal
align 4
ram_info RAM_INFO
hist_pos dd ?
hist_cpu rd HIST_LEN
hist_mem rd HIST_LEN
procs_end dd ?
procs rb MAX_PROCS * sizeof.PROC
endg
+231
View File
@@ -0,0 +1,231 @@
; Autorun tab: the programs /sys/LAUNCHER starts from /sys/settings/autorun.dat.
; A line is: program parameters delay; "text" may hold spaces, # starts
; a comment. A program after # is turned off: the button or Space turns it
; on or off in the file.
struct AR
prog dd ?
params dd ?
delay dd ?
num dd ? ; of the entry
off db ? ; 1: after #, turned off
ends
; Read the file, its lines into the list.
autorun_load:
mcall SF_FILE, autorun_info ; its size; read a byte more to see
mov ecx, [autorun_bdfe.FileSizeLow] ; its end
test eax, eax
jz @f
xor ecx, ecx
@@:
inc ecx
mov [autorun_file.Count], ecx
inc ecx ; a # more, then 0
inc ecx
mcall SF_SYS_MISC, SSF_MEM_REALLOC, , [autorun_file.Buffer]
mov [autorun_file.Buffer], eax
mov [autorun_save.Buffer], eax
mov ebp, [list.view]
test eax, eax
jz list_done
mcall SF_FILE, autorun_file
cmp eax, 6 ; the end of the file: all of it
je @f
xor ebx, ebx
@@:
mov esi, [autorun_file.Buffer]
mov byte [esi + ebx], 0
add ebx, esi
mov edi, esi ; the rows: at most the bytes that
xor edx, edx ; may end a line, 0..13, and one
.count:
inc edx
@@:
cmp edi, ebx
jae @f
cmp byte [edi], 14
inc edi
jb .count
jmp @b
@@:
imul ecx, edx, 4 + sizeof.AR ; the view, then the rows
push ebx edx
mcall SF_SYS_MISC, SSF_MEM_REALLOC, , [list.view]
pop edx ebx
mov [list.view], eax
mov ebp, eax
lea edi, [eax + edx*4]
test eax, eax
jz list_done
.line:
cmp esi, ebx
jae list_done
push esi
@@:
lodsb ; find the end of the line
cmp al, 13
je @f
cmp al, 10
je @f
test al, al
jnz @b
@@:
mov byte [esi - 1], 0
xchg esi, [esp]
call get_token ; the row goes to edi, its pointer to ebp
cmp byte [eax], 0 ; empty line
je .next
cmp word [eax], "#/" ; a program turned off
je @f
cmp byte [eax], "#" ; comment
je .next
@@:
mov dl, [eax]
mov [ebp], edi
add ebp, 4
stosd ; AR.prog, params, delay
call get_token
stosd
call get_token
stosd
mov eax, ebp
sub eax, [list.view]
shr eax, 2
stosd
cmp dl, "#" ; AR.off
sete al
stosb
.next:
pop esi
jmp .line
; Put # before the selected program or take it away and save the file.
autorun_toggle:
cmp [list.count], 0 ; no rows, maybe no buffer
je .done
mcall SF_FILE, autorun_file ; the file again, as it is
cmp eax, 6 ; all of it
jne .done
mov edi, [list.key] ; AR.prog: the line in the buffer
mov ecx, [autorun_file.Buffer]
add ecx, ebx
sub ecx, edi ; not past the end: the file was cut
jbe .done
cmp byte [edi], "#"
je .on
lea esi, [edi + ecx - 1] ; one byte on from the end
lea edi, [esi + 1]
std
rep movsb
cld
mov byte [edi], "#"
inc ebx
jmp .save
.on:
lea esi, [edi + 1]
dec ecx
rep movsb
dec ebx
.save:
mov [autorun_save.Count], ebx
mcall SF_FILE, autorun_save
call autorun_load
jmp list_rows
.done:
ret
; esi -> text; out: eax -> the next word or "text", cut with zero; esi after it
get_token:
mov eax, esi
mov dh, [esi]
test dh, dh
jz .done
inc esi
cmp dh, " " ; skip blanks
jbe get_token
mov cx, " " shl 8 ; a word ends with a blank
cmp dh, '"'
jne .next
mov cx, '"' ; "text" with the quote
mov eax, esi
.next:
mov dh, [esi]
test dh, dh
jz .done
inc esi
sub dh, cl ; cl..cl + ch ends it
cmp dh, ch
ja .next
mov byte [esi - 1], 0
.done:
ret
autorun_bar:
BAR BAR_BUTTON, sz_ar_toggle, sc.work_button
db BAR_END
autorun_list LIST autorun_cols, autorun_cols_end, autorun_cols, nothing, nothing, autorun_keys, AR.off, 0, 0, 0, 0, 0, 0 ; the view on the heap
autorun_keys:
HOTKEY KEY_SPACE, autorun_toggle
db 0
autorun_cols:
COL sz_col_num, AR.num, KIND_NUM, ID_W
COL sz_col_program, AR.prog, KIND_STR, 0
COL sz_col_params, AR.params, KIND_STR, COL_W
COL sz_col_delay, AR.delay, KIND_STR, COL_W
autorun_cols_end:
if lang eq ru_RU
sz_tab_autorun db "Автозагрузка", 0
sz_col_program db "Программа", 0
sz_col_params db "Параметры", 0
sz_col_delay db "Задержка", 0
sz_ar_toggle db "Включить/выключить", 0
else if lang eq es_ES
sz_tab_autorun db "Inicio", 0
sz_col_program db "Programa", 0
sz_col_params db "Parámetros", 0
sz_col_delay db "Retardo", 0
sz_ar_toggle db "Activar/desactivar", 0
else
sz_tab_autorun db "Autorun", 0
sz_col_program db "Program", 0
sz_col_params db "Parameters", 0
sz_col_delay db "Delay", 0
sz_ar_toggle db "Turn on/off", 0
end if
autorun_info FileInfoBlock SSF_GET_INFO, 0, 0, 0, autorun_bdfe, 0, sz_autorun
autorun_file FileInfoBlock SSF_READ_FILE, 0, 0, 0, 0, 0, sz_autorun ; the buffer on
autorun_save FileInfoBlock SSF_CREATE_FILE, 0, 0, 0, 0, 0, sz_autorun ; the heap
sz_autorun db "/sys/settings/autorun.dat", 0
virtual at tab_data ; only the open tab uses it
autorun_bdfe FileInfoA
AUTORUN_DATA = $ - tab_data
end virtual
+343
View File
@@ -0,0 +1,343 @@
; Disks tab: the partitions in a sortable list, the used space as a bar
; across what the other columns leave. The kernel does not report free
; space, so for memory disks (/rd, /tmp*) the space taken by files is summed
; up. The disks are found in a thread, the tab is drawn at once.
struct DISK
num dd ? ; in the order found, the key of the row
icon dd ? ; in ICONS18, by the kind of the disk
fill dd ? ; used, 1/1024 of the size, -1: unknown
used dd ? ; KB, -1: unknown
total dd ? ; KB
name rb 16 ; the path
label rb 28
ends
MAX_DISKS = 16
WALK_MAX = 1024 ; path length
WALK_DEPTH = 16
; Start the thread that finds the disks.
disks_scan:
xor eax, eax
mov [list.count], eax
mov [list.first], eax
mov [disk_n], eax
mov [walk_stop], eax
inc [walking]
mcall SF_THREAD_CONTROL, SSF_CREATE_THREAD, walker, walk_stack_top
inc eax ; -1: no thread, nothing to wait for
jnz @f
and [walking], 0
@@:
ret
; The walker found more: the view of the disks found so far, sorted.
disks_update:
xor eax, eax
xchg eax, [walk_new]
test eax, eax
jz .done
mov esi, disks
mov ebp, disks_view
mov ecx, [disk_n]
@@:
mov [ebp], esi
add ebp, 4
add esi, sizeof.DISK
loop @b
call list_done
jmp list_rows
.done:
ret
disks_open: ; the selected disk in Eolite
cmp [list.count], 0
je .done
imul edx, [list.key], sizeof.DISK ; DISK.num
add edx, disks + DISK.name
mov esi, sz_eolite_path
jmp run_app
.done:
ret
;-------------------------------------------------------------------------------
; The thread that finds the disks and sums up the files of memory disks.
disks_find:
xor ebp, ebp ; device index in "/"
.device:
mov word [walk_path], "/"
call read_entry
jnz .done
mov edi, walk_path + 1
call fmt_str
mov ecx, edi ; end of "/device"
xor edx, edx ; partition index
.partition:
mov byte [ecx], 0
xchg ebp, edx
call read_entry
xchg ebp, edx
jnz .device
cmp [disk_n], MAX_DISKS
jae .done
mov edi, ecx
mov byte [edi], "/"
inc edi
call fmt_str
call disk_add
jmp .partition
.done:
ret
; Read entry ebp of the folder [walk_path], ebp to the next one; out:
; ZF = 1 if read, esi -> its name
read_entry:
cmp [walk_stop], 0 ; asked to stop: the thread ends
jne walker.stop
mov [fs_read.Position], ebp
inc ebp
mcall SF_FILE, fs_read
mov esi, fs_entry.FileName
test eax, eax
ret
; [walk_path] = root of the partition, edi -> its end
disk_add:
pusha
mcall SF_FILE, fs_info
test eax, eax
jnz .done
mov eax, [disk_n]
imul ebx, eax, sizeof.DISK
add ebx, disks
mov [ebx + DISK.num], eax
mov ax, word [walk_path + 1] ; the kind by the device
mov esi, disk_icons - 3
@@:
add esi, 3
cmp word [esi], 0
je @f
cmp [esi], ax
jne @b
@@:
movzx eax, byte [esi + 2]
mov [ebx + DISK.icon], eax
mov esi, walk_path
lea edi, [ebx + DISK.name]
mov ecx, DISK.label - DISK.name
call copy_cut
mov esi, fs_buf + FileInfoA.FileName ; of the partition
lea edi, [ebx + DISK.label]
mov ecx, sizeof.DISK - DISK.label
call copy_cut
mov eax, [fs_buf + FileInfoA.FileSizeLow]
mov edx, [fs_buf + FileInfoA.FileSizeHigh]
shrd eax, edx, 10
shr edx, 10 ; 4 TB and more: unknown
jz @f
or eax, -1
@@:
mov [ebx + DISK.total], eax
or dword [ebx + DISK.used], -1
or dword [ebx + DISK.fill], -1
inc [disk_n] ; listed when it is all there
mov [walk_new], ebx
test eax, eax
jz .done
mov eax, dword [walk_path + 1]
cmp ax, "rd"
je @f
and eax, 0xFFFFFF
cmp eax, "tmp"
jne .done
@@:
xor ecx, ecx
xor edx, edx
mov edi, [esp + PUSHA_EDI] ; the end of the path
call disk_walk
cmp ecx, [ebx + DISK.total] ; not more used than there is
jbe @f
mov ecx, [ebx + DISK.total]
@@:
mov [ebx + DISK.used], ecx
xchg eax, ecx
mov edx, 1024
mul edx
div dword [ebx + DISK.total]
mov [ebx + DISK.fill], eax
mov [walk_new], ebx
.done:
popa
ret
; esi -> text, edi -> a field of ecx bytes: the text, cut to fit it, not in
; the middle of a character
copy_cut:
rep movsb
@@:
dec edi
mov al, [edi]
and al, 0xC0
cmp al, 0x80
je @b
mov [edi], cl
ret
; The thread.
walker:
call disks_find
.stop:
and [walking], 0
mcall SF_TERMINATE_PROCESS
; Ask the walker to stop and wait till it is gone.
stop_walker:
mov [walk_stop], 1
@@:
and [walk_new], 0
cmp [walking], 0
je @f
mcall SF_SLEEP, 1
jmp @b
@@:
ret
; Add the size of files under [walk_path] to ecx, KB; edi -> end of the path,
; edx = depth
disk_walk:
pusha
xor ebp, ebp ; index in the folder
inc edx
.next:
call read_entry
jnz .done
test byte [fs_entry.Attributes], FA_LABEL
jnz .next
test byte [fs_entry.Attributes], FA_FOLDER
jnz .folder
mov eax, [fs_entry.FileSizeLow]
add eax, 1023
shr eax, 10
add ecx, eax
jmp .next
.folder:
cmp byte [esi], "." ; skip "." and ".."
jne @f
cmp byte [esi + 1], 0
je .next
cmp word [esi + 1], "."
je .next
@@:
cmp edx, WALK_DEPTH
jae .next
lea eax, [edi + 264]
cmp eax, walk_path + WALK_MAX
jae .next
push edi
mov byte [edi], "/"
inc edi
call fmt_str
call disk_walk
pop edi
mov byte [edi], 0
jmp .next
.done:
mov [esp + PUSHA_ECX], ecx
popa
ret
disks_bar:
BAR BAR_BUTTON, sz_open, sc.work_button
db BAR_END
disks_list LIST disks_cols, disks_cols_end, disks_cols + sizeof.COL, nothing, disks_open, disks_keys, 0, 0, 0, 0, 0, 0, tab_data
disks_keys:
HOTKEY KEY_ENTER, disks_open
db 0
disks_cols:
COL sz_col_num, DISK.icon, KIND_ICON, ID_W
COL sz_col_name, DISK.name, KIND_TEXT, COL_W
COL sz_col_label, DISK.label, KIND_TEXT, COL_W
COL sz_pct, DISK.fill, KIND_BAR, 0
COL sz_used, DISK.used, KIND_SIZE, COL_W
COL sz_col_size, DISK.total, KIND_SIZE, COL_W
disks_cols_end:
if lang eq ru_RU
sz_col_size db "Размер", 0
sz_col_label db "Метка", 0
sz_open db "Открыть", 0
else if lang eq es_ES
sz_col_size db "Tamaño", 0
sz_col_label db "Etiqueta", 0
sz_open db "Abrir", 0
else
sz_col_size db "Size", 0
sz_col_label db "Label", 0
sz_open db "Open", 0
end if
sz_eolite_path db "/sys/File Managers/EOLITE", 0
; the first two letters of the device, the icon; the last one for the others
disk_icons db "rd", 58, "tm", 51, "fd", 5, "cd", 19, "us", 57, 0, 0, 50
fs_read FileInfoBlock SSF_READ_FOLDER, 0, 1, 1, fs_buf, 0, walk_path ; cp866
; names, one entry from Position on
fs_info FileInfoBlock SSF_GET_INFO, 0, 3, 0, fs_buf, 0, walk_path ; UTF-8
; volume label
uglobal
disk_n dd ? ; the disks the walker found
walking dd ?
walk_stop dd ?
walk_new dd ?
rb 1024
walk_stack_top:
endg
virtual at tab_data ; only the open tab uses it
disks_view rd MAX_DISKS
disks rb MAX_DISKS * sizeof.DISK
fs_buf FileInfoHeader ; then an entry of a folder; a
fs_entry FileInfoA ; partition from fs_buf on
walk_path rb WALK_MAX
DISKS_DATA = $ - tab_data
end virtual
+92
View File
@@ -0,0 +1,92 @@
; Drivers tab: the drivers loaded by the kernel (function 68.31).
struct DRV
num dd ? ; in the list, the key of the row
name rb 16 ; from here on the item of the kernel
next dd ?
handle dd ? ; the kernel keeps the previous item here
base dd ?
start dd ? ; the entry of the driver
service dd ?
ends
MAX_DRIVERS = 64
; The drivers the kernel has now.
drivers_scan:
mcall SF_SYS_MISC, SSF_GET_DRIVER_DATA, 1
mov esi, ecx ; the last driver
mov edx, ebx ; the first one
mov ebp, drivers_view
mov edi, drivers + DRV.name
.next:
cmp ebp, drivers_view + MAX_DRIVERS*4
jae list_done
mcall SF_SYS_MISC, SSF_GET_DRIVER_DATA, 2
test eax, eax
jnz list_done
lea eax, [edi - DRV.name]
mov [ebp], eax
add ebp, 4
lea eax, [ebp - drivers_view]
shr eax, 2
mov dword [edi + DRV.num - DRV.name], eax
mov eax, dword [edi + DRV.next - DRV.name]
mov dword [edi + DRV.handle - DRV.name], edx
add edi, sizeof.DRV
cmp edx, esi
mov edx, eax
jne .next
jmp list_done
drivers_load: ; RUN with the name of the driver to type
mov esi, sz_run_path
mov edx, sz_loaddrv
jmp run_app
drivers_bar:
BAR BAR_BUTTON, sz_load, sc.work_button
db BAR_END
drivers_list LIST drivers_cols, drivers_cols_end, drivers_cols, nothing, nothing, no_keys, 0, 0, 0, 0, 0, 0, tab_data
drivers_cols:
COL sz_col_num, DRV.num, KIND_NUM, ID_W
COL sz_col_name, DRV.name, KIND_TEXT, 0
COL sz_col_handle, DRV.handle, KIND_HEX, COL_W
COL sz_col_base, DRV.base, KIND_HEX, COL_W
COL sz_col_service, DRV.service, KIND_HEX, COL_W
drivers_cols_end:
if lang eq ru_RU
sz_tab_drivers db "Драйверы", 0
sz_col_handle db "Дескриптор", 0
sz_col_base db "База", 0
sz_col_service db "Сервис", 0
sz_load db "Загрузить...", 0
else if lang eq es_ES
sz_tab_drivers db "Controladores", 0
sz_col_handle db "Manejador", 0
sz_col_base db "Base", 0
sz_col_service db "Servicio", 0
sz_load db "Cargar...", 0
else
sz_tab_drivers db "Drivers", 0
sz_col_handle db "Handle", 0
sz_col_base db "Base", 0
sz_col_service db "Service", 0
sz_load db "Load...", 0
end if
sz_loaddrv db "/sys/LOADDRV ", 0
virtual at tab_data ; only the open tab uses it
drivers_view rd MAX_DRIVERS
drivers rb MAX_DRIVERS * sizeof.DRV
DRIVERS_DATA = $ - tab_data
end virtual
+532
View File
@@ -0,0 +1,532 @@
; Performance tab: CPU, temperature when there is a sensor, memory and
; network history in rows, lines between them. A row: the icon, the title
; and the items on the left, the graph on the right.
GRAPH_STEP = 4 ; pixels per sample
INFO_W = 256 + 2*PAD + ICON ; the icon, the title, the items, PAD
NET_DEVICES = 16 ; of the kernel
struct G ; a graph
title dd ?
hist dd ? ; dwords up to the top
hist2 dd ? ; 0, the network: received, sent
info dd ? ; items left of the graph
unit dd ? ; of the value in the title
top dd ? ; -> the top of the scale
on dd ? ; -> not 0 if shown
icon dd ? ; before the title
ends
struct ITEM ; a line left of a graph
text dd ?
get dd ? ; edi -> the text; out: edi after it
ends
struct NET_BYTES ; of all the devices
rx dq ?
tx dq ?
ends
perf_draw: ; eax = TAB.draw: with the frames,
lea esi, [eax - TAB.update] ; TAB.update: esi = 0, without
mov edi, shown ; the graphs there is data for
mov eax, graphs
.shown:
mov edx, [eax + G.on]
cmp dword [edx], 0
je @f
stosd
@@:
add eax, sizeof.G
cmp eax, graphs_end
jb .shown
sub edi, shown
shr edi, 2
xchg edi, [shown_n]
cmp edi, [shown_n] ; one came or went: all again
je .draw
test esi, esi
jz draw_window
.draw:
xor ebp, ebp
.graph:
call graph_frame
call perf_graph
inc ebp
cmp ebp, [shown_n]
jb .graph
ret
; The button of the bar.
perf_cpuid:
mov esi, sz_cpuid_path
jmp run_plain
; ebp = graph; out: ebx = x shl 16 + w, ecx = y shl 16 + h of its frame.
; Between the rows a line, PAD from both.
graph_frame:
mov eax, [area_h]
dec eax
xor edx, edx
div [shown_n] ; from a row to the next one
mov ecx, ebp
imul ecx, eax
add ecx, AREA_Y + 1 + PAD
shl ecx, 16
sub eax, 2*PAD + 1
mov cx, ax
mov ebx, (3*PAD + 1 + INFO_W) shl 16
mov bx, word [area_w]
sub bx, 2 + 3*PAD + INFO_W
ret
; ecx = y shl 16 of a frame: the line between its row and the one above
row_line:
pusha
shr ecx, 16
sub ecx, PAD + 1 ; the middle of the gap above
shl ecx, 16
inc ecx
mov ebx, (PAD + 1) shl 16
mov bx, word [area_w]
sub bx, 2
mcall SF_DRAW_RECT, , , [sc.work_graph]
popa
ret
; ebp = graph, ebx and ecx = its frame, esi = 0: no frame
perf_graph:
pusha
test esi, esi
jz .title
mov edx, [sc.work_light]
call frame_rect
call row_line ; the first one on the panel border
.title:
mov ebp, [shown + ebp*4]
mov esi, [ebp + G.hist]
mov edx, [ebp + G.hist2]
mov edi, [hist_pos] ; the last value
mov eax, [esi + edi*4]
test edx, edx
jz @f
add eax, [edx + edi*4] ; the network: both ways
mov edi, text_buf
call fmt_rate
jmp .titled
@@:
mov edi, text_buf
call fmt_uint
mov eax, [ebp + G.unit]
call fmt_unit
.titled:
call info_lines ; the lines left of it
mov eax, [ebp + G.top] ; the top: 100 %, TjMax, the network:
mov eax, [eax] ; the largest rate of the columns
add ebx, 1 shl 16 - 2 ; bars inside the frame, newest on the right
add ecx, 1 shl 16 - 2
movzx edi, bx
test edx, edx
jz .scaled
call net_scale
.scaled:
mov [scale], eax
mov ebp, [hist_pos]
.bar: ; the network: received on the left,
mov eax, GRAPH_STEP ; sent on the right, lighter
cmp edi, eax
jae @f
mov eax, edi
@@:
mov bx, ax
sub edi, eax
pusha
shl edi, 16
add ebx, edi
mov edi, [sc.work_button]
test edx, edx
jz .last
mov eax, ebx
shr ax, 1
sub bx, ax
call .value
shl ebx, 16
add eax, ebx
xchg eax, ebx
mov esi, edx
mov eax, [sc.work_light] ; sent: half way to the background
mov edx, edi
call mix
xchg eax, edi
.last:
call .value
popa
dec ebp
and ebp, HIST_LEN - 1
test edi, edi
jnz .bar
test edx, edx ; the network: its top at the top right
jz .critical
mov edi, text_buf
mov eax, [scale]
call fmt_rate
mov ebx, [area_w]
shl ebx, 16
mov bx, [esp + PUSHA_ECX + 2] ; y of the frame
add ebx, ((-6 - INFO_W + ICON + PAD) shl 16) + 4
call info_value
@@:
popa
ret
.critical: ; the temperature: a line 10 below
cmp esi, hist_temp ; the top
jne @b
movzx eax, cx
imul eax, 10
div [scale] ; edx = G.hist2 = 0 here
shl eax, 16
add ecx, eax
mov cx, 1
mov ebx, [esp + PUSHA_EBX] ; the frame
add ebx, 1 shl 16 - 2
mcall SF_DRAW_RECT, , , [red]
jmp @b
; esi + ebp*4 -> value, edi = color: its bar at the bottom, the background
; above it, not one over the other, so it does not flicker
.value:
pusha
mov eax, [esi + ebp*4]
cmp eax, [scale] ; not over the top
jb @f
mov eax, [scale]
@@:
movzx esi, cx
mul esi
div [scale]
xchg ebp, eax
sub cx, bp
mcall SF_DRAW_RECT, , , [sc.work_light]
movzx edx, cx
shl edx, 16
add ecx, edx
mov cx, bp
mcall SF_DRAW_RECT, , , edi
popa
ret
; esi, edx -> the history received and sent, edi = the width of the graph;
; out: eax = its top, the largest rate shown up to 1, 2, 5, 10, 20, 50...
; bit/s while it fits
net_scale:
push edi
mov ebp, [hist_pos]
xor eax, eax
.max:
cmp eax, [esi + ebp*4]
jae @f
mov eax, [esi + ebp*4]
@@:
cmp eax, [edx + ebp*4]
jae @f
mov eax, [edx + ebp*4]
@@:
dec ebp
and ebp, HIST_LEN - 1
sub edi, GRAPH_STEP
jg .max
pop edi
cmp eax, 2000000000
ja .done
xor ebp, ebp
inc ebp
@@:
cmp ebp, eax
jae @f
add ebp, ebp
cmp ebp, eax
jae @f
lea ebp, [ebp*4 + ebp]
shr ebp, 1
cmp ebp, eax
jae @f
add ebp, ebp
jmp @b
@@:
xchg eax, ebp
.done:
ret
; text_buf on the right of an item line at ebx = x shl 16 + y
info_value:
pusha
mov ecx, [sc.work_text]
mov edx, text_buf
mov eax, edx
call text_width
neg eax
add eax, INFO_W - ICON - PAD
shl eax, 16
add ebx, eax
call draw_text
popa
ret
; ebp -> graph, ecx = y shl 16 + h of its frame, text_buf = its value:
; the title and the items a line each as fit, the label on the left, the
; value on the right. The ITEMs end with 0.
info_lines:
pusha
movzx esi, cx ; the height left
mov ebx, ((2*PAD + 1) shl 16) + INFO_W
mcall SF_DRAW_RECT, , , [sc.work_light]
mov ebx, ecx ; the icon, the lines after it
shr ebx, 16
add ebx, (2*PAD + 1) shl 16 - 1
mov eax, [ebp + G.icon]
mov edx, [sc.work_light]
call draw_icon
add ebx, ((ICON + PAD) shl 16) + 1
mov edx, [ebp + G.title]
mov ebp, [ebp + G.info]
mov ecx, [sc.work_text]
jmp .line
.item:
mov edx, [ebp + ITEM.text]
test edx, edx
jz .done
mov edi, text_buf
pusha
call [ebp + ITEM.get]
popa
add ebp, sizeof.ITEM
.line:
sub esi, 16
jb .done
call draw_text
mov eax, edx ; the value in the rest of the line
call text_width
pusha
mov ebx, INFO_W - 8 - ICON - PAD
mov edx, text_buf
mov edi, edx
call fmt_clip
popa
call info_value
add ebx, 16
jmp .item
.done:
popa
ret
; Once a second: the bytes of the network devices, but the loopback.
net_sample:
pusha
mov edi, net_sum
xor eax, eax
mov ecx, (net_last - net_sum) / 4 ; and net_up
rep stosd
mov ebx, (NET_DEVICES - 1) shl 8
.device:
push ebx ; bl = SSF_DEVICE_TYPE
mcall SF_NETWORK_GET
test eax, eax ; -1: none, 0: the loopback
jle .next
inc [net_up]
mov bl, SSF_RX_BYTE_COUNT
mcall SF_NETWORK_GET
add dword [net_sum.rx], eax
adc dword [net_sum.rx + 4], ebx
mov ebx, [esp]
mov bl, SSF_TX_BYTE_COUNT
mcall SF_NETWORK_GET
add dword [net_sum.tx], eax
adc dword [net_sum.tx + 4], ebx
.next:
pop ebx
dec bh
jns .device
mov ecx, [hist_pos]
mov esi, net_sum.rx
mov ebx, hist_rx
call .rate
mov ebx, hist_tx
call .rate
or [net_primed], -1
popa
ret
.rate: ; since the last second, 0 at first
mov eax, [esi]
mov edx, [esi + 4]
sub eax, [edi]
sbb edx, [edi + 4]
movsd ; the sum is the last one now
movsd
jae @f
xor eax, eax ; a device went away
@@:
shl eax, 3 ; bits
and eax, [net_primed]
mov [ebx + ecx*4], eax
ret
; The items of the lines left of the graphs: edi -> the text; out:
; edi after it.
get_freq:
mcall SF_SYSTEM, SSF_GET_CPU_FREQUENCY
mov ecx, 1000000
call fmt_quot
mov eax, sz_mhz
jmp fmt_unit
get_uptime:
mcall SF_SYSTEM_GET, SSF_TIME_COUNT
xor edx, edx
mov ecx, 100
div ecx
jmp fmt_time
get_threads:
mov eax, [procs_end]
sub eax, procs
mov ecx, sizeof.PROC ; then fmt_quot
; eax / ecx, edx = the remainder
fmt_quot:
xor edx, edx
div ecx
jmp fmt_uint
get_used:
mov eax, [ram_info.total]
sub eax, [ram_info.free]
jmp @f
get_free:
mov eax, [ram_info.free]
jmp @f
get_total:
mov eax, [ram_info.total]
@@:
shl eax, 2 ; pages to KB
jmp fmt_size
get_rx:
mov esi, net_sum.rx
mov ebx, hist_rx
jmp @f
get_tx:
mov esi, net_sum.tx
mov ebx, hist_tx
@@: ; the rate, then the total
mov eax, [hist_pos]
mov eax, [ebx + eax*4]
call fmt_rate
mov word [edi], " ("
scasw
mov eax, [esi]
mov edx, [esi + 4]
shrd eax, edx, 10
call fmt_size
mov word [edi], ")"
inc edi
ret
graphs:
G sz_col_cpu, hist_cpu, 0, cpu_info, sz_pct, pct_top, pct_top, 48
temp_graph G sz_temp, hist_temp, 0, temp_info, sz_deg, tjmax, temp_on, 68
G sz_col_mem, hist_mem, 0, mem_info, sz_pct, pct_top, pct_top, 51
G sz_net, hist_rx, hist_tx, net_info, 0, pct_top, net_up, 12
graphs_end:
pct_top dd 100
perf_bar:
BAR BAR_BUTTON, sz_cpuid_path + 5, sc.work_button ; "CPUID"
db BAR_END
sz_cpuid_path db "/sys/CPUID", 0
cpu_info ITEM sz_freq, get_freq
ITEM sz_uptime, get_uptime
ITEM sz_threads, get_threads
dd 0
mem_info ITEM sz_used, get_used
ITEM sz_col_free, get_free
ITEM sz_total, get_total
dd 0
net_info ITEM sz_received, get_rx
ITEM sz_sent, get_tx
dd 0
temp_info ITEM sz_crit, get_tjmax ; Intel
no_info dd 0
uglobal
align 4
shown rd 4 ; -> graphs
shown_n dd ?
net_primed dd ?
scale dd ? ; of the bars being drawn
net_sum NET_BYTES
net_up dd ? ; the devices, but the loopback
net_last NET_BYTES
hist_rx rd HIST_LEN ; bits a second
hist_tx rd HIST_LEN
endg
+98
View File
@@ -0,0 +1,98 @@
; Processes tab: the threads in a sortable list.
; The threads to show, then the whole list or the rows only.
procs_draw:
call procs_filter
jmp list_draw
procs_update:
call procs_filter
jmp list_rows
; The threads to show, without the system ones unless asked.
procs_filter:
mov esi, procs
mov ebp, procs_view
.next:
cmp esi, [procs_end]
jae list_done
cmp [show_system], 0
jne .add
cmp esi, procs ; IDLE
je .skip
cmp byte [esi + PROC.name], "@"
je .skip
cmp dword [esi + PROC.name], "OS"
je .skip
.add:
mov [ebp], esi
add ebp, 4
.skip:
add esi, sizeof.PROC
jmp .next
procs_button: ; edx = button id
jmp [.btns + (edx - BTN_OWN)*4]
.btns dd .system, procs_info, procs_kill, procs_run ; as in procs_bar
.system:
xor [show_system], 1
jmp draw_window
; The buttons: Run..., End, Details.
procs_run:
mov esi, sz_run_path
jmp run_plain
procs_kill: ; the key of a row is its PID
mcall SF_SYSTEM, SSF_TERMINATE_THREAD_ID, [list.key]
ret
procs_info:
mcall SF_SYSTEM, SSF_GET_THREAD_SLOT, [list.key]
test eax, eax
jz .done
mov edi, text_buf
call fmt_uint
mov esi, sz_tinfo_path
mov edx, text_buf
jmp run_app
.done:
ret
procs_bar:
BAR BAR_CHECK, sz_system, show_system
BAR BAR_BUTTON, sz_info, sc.work_button
BAR BAR_BUTTON, sz_kill, red
BAR BAR_GAP, 0, 0 ; away from End
BAR BAR_BUTTON, sz_run, green
db BAR_END
procs_list LIST procs_cols, procs_cols_end, procs_cols, nothing, procs_info, procs_keys, 0, 0, 0, 0, 0, 0, tab_data
procs_keys:
HOTKEY KEY_ENTER, procs_info
HOTKEY KEY_DEL, procs_kill
db 0
procs_cols:
COL sz_col_id, PROC.pid, KIND_NUM, ID_W
COL sz_col_name, PROC.name, KIND_TEXT, 0
COL sz_col_cpu, PROC.cpu, KIND_PCT, COL_W
COL sz_col_mem, PROC.mem, KIND_SIZE, COL_W
procs_cols_end:
uglobal
show_system db ?
endg
virtual at tab_data ; only the open tab uses it
procs_view rd MAX_PROCS
PROCS_DATA = $ - tab_data
end virtual
+344
View File
@@ -0,0 +1,344 @@
; SPDX-License-Identifier: GPL-2.0-only
;
; Task manager. A tab is a row of the `tabs` table: its caption, list
; and handlers. To add a tab, add a row and an .inc file with the handlers.
include "../../KOSfuncs.inc"
include "../../macros.inc"
include "../../develop/libraries/box_lib/box_lib.mac"
include "../../develop/libraries/libs-dev/libio/libio.inc"
format meos 01
entry start
include "gui.inc"
include "hwmon.inc"
include "list.inc"
include "locale.inc"
include "sensors.inc"
include "stats.inc"
include "window.inc"
include "tabs/autorun.inc"
include "tabs/disks.inc"
include "tabs/drivers.inc"
include "tabs/perf.inc"
include "tabs/procs.inc"
;-------------------------------------------------------------------------------
start:
mcall SF_SET_EVENTS_MASK, EVENTS
mcall SF_SYS_MISC, SSF_LOAD_DLL, box_lib_path
test eax, eax
jz exit
xchg ecx, eax
mov ebp, box_lib ; the names become the procs
.import:
mov ebx, ecx
.export:
mov esi, [ebx]
test esi, esi
jz exit
add ebx, 8
mov edi, [ebp]
@@:
lodsb
scasb
jne .export
test al, al
jnz @b
mov edx, [ebx - 4]
mov [ebp], edx
add ebp, 4
cmp dword [ebp], 0
jne .import
mcall SF_SYS_MISC, SSF_HEAP_INIT
mcall SF_SYS_MISC, SSF_MEM_OPEN, icons_name, 0, 0 ; of @RESHARE
mov [icons], eax
call sensors_init
reopen:
call open_tab
redraw:
call draw_window
still:
mcall SF_SYSTEM_GET, SSF_TIME_COUNT
mov ebx, [next_tick]
sub ebx, eax
jg .wait
add eax, TICK
mov [next_tick], eax
call sample
mcall SF_THREAD_INFO, pinfo, -1
test [pinfo.wnd_state], WND_MINIMIZED + WND_ROLLED_UP
jnz still
mov eax, TAB.update
call tab_call
jmp still
.wait:
cmp [repeat_at], 0 ; an arrow held: the mouse again soon
je @f
mov ebx, 4
@@:
mcall SF_WAIT_EVENT_TIMEOUT
dec eax ; EV_REDRAW
jz redraw
dec eax ; EV_KEY
jz key
dec eax ; EV_BUTTON
jz button
cmp al, EV_MOUSE - EV_BUTTON ; the mouse, or the time with
je .mouse ; it held
cmp al, EV_IDLE - EV_BUTTON
jne still
cmp [repeat_at], 0 ; a held arrow when it is time
je still
dec [repeat_at]
jnz still
.mouse:
mov eax, TAB.mouse
call tab_call
jmp still
key:
mcall SF_GET_KEY
shr eax, 8
cmp al, KEY_ESC
je exit
cmp al, KEY_TAB ; the next tab
je next_tab
call tab_list ; other keys are for lists
jz still
call list_key
jmp still
button:
mcall SF_GET_BUTTON
shr eax, 8
cmp eax, 1
je exit
cmp eax, BTN_OWN
jae .own
sub eax, BTN_TAB
cmp eax, BTN_SHUTDOWN - BTN_TAB
jb switch_tab
mov esi, sz_end_path
call run_plain
jmp still
.own:
xchg eax, edx
mov eax, TAB.button
call tab_call
jmp still
next_tab:
mov eax, [cur_tab]
inc eax
cmp eax, NTABS
jb switch_tab
xor eax, eax ; then switch_tab
switch_tab: ; eax = tab
cmp eax, [cur_tab] ; the open one: nothing to do
je still
push eax
call tab_list ; the old tab keeps its list
mov esi, list
call copy_list
pop [cur_tab]
jmp reopen
exit:
call stop_walker
mcall SF_TERMINATE_PROCESS
; Open the current tab: its list, then its activate handler.
open_tab:
and [repeat_at], 0
call stop_walker
call tab_list
mov esi, edi
mov edi, list
call copy_list
mov eax, TAB.activate
tab_call: ; eax = handler in TAB
imul ecx, [cur_tab], sizeof.TAB
movzx ecx, word [tabs + ecx + eax]
jmp ecx
nothing:
ret
; out: edi -> list of the current tab or 0, ZF = 1 if 0
tab_list:
imul edi, [cur_tab], sizeof.TAB
movzx edi, word [tabs + edi + TAB.list]
test edi, edi
ret
; Copy the list at esi to edi unless ZF = 1: the tab has none.
copy_list:
jz @f
mov ecx, sizeof.LIST / 4
rep movsd
@@:
ret
;-------------------------------------------------------------------------------
; Settings
MIN_W = 640 ; fits the longest bottom bar (ru_RU)
MIN_H = 400 ; four graphs are still readable
TICK = 100 ; statistics period, 1/100 s
HIST_LEN = 1024 ; power of 2, the bars of a 4K wide window
MAX_PROCS = 256
; Layout
PAD = 8 ; margins and gaps
TOP = 12 ; above the tabs
TAB_H = 24
AREA_Y = TOP + TAB_H - 1 ; top of the panel, the bottom of the tabs
BTN_H = 24
BTN_PAD = 12 ; text to the sides of a button
CHECK = 14 ; checkbox
ICON = 18 ; icons of @RESHARE
TEXT_CHARS = 63 ; the longest text drawn
TEXT_H = 14 ; 8x16 glyphs look centered as 14 lines
; The window and the text
EVENTS = EVM_REDRAW + EVM_KEY + EVM_BUTTON + EVM_MOUSE + EVM_MOUSE_FILTER
WIN_STYLE = 0x73000000 ; skinned, a caption, coordinates in
; the client area, not filled: drawn
TEXT_UTF8 = 0xB0000000 ; asciiz, UTF-8, 8x16
WND_MAXIMIZED = 1 ; process_information.wnd_state
WND_MINIMIZED = 2
WND_ROLLED_UP = 4
; Lists
COL_W = 112
ID_W = 3*8 + 2*CELL_PAD ; a number: ID, Nº or #, the arrow
KIND_TEXT = 0 ; zero ended text in the row, sorted ascending
KIND_STR = 1 ; pointer to text
KIND_NUM = 2
KIND_PCT = 3 ; from here on sorted down at first
KIND_SIZE = 4
KIND_HEX = 5
KIND_BAR = 6 ; 1/1024 of the cell filled
KIND_ICON = 7 ; in ICONS18
HDR_H = 24 - 2 ; 24 with its lines, as an arrow
ROW_H = 20
SB_W = 24 ; scrollbar, as high as the list
CELL_PAD = 8
; Keys and mouse buttons
KEY_TAB = 9
KEY_ENTER = 13
KEY_SPACE = 32
KEY_ESC = 27
KEY_DOWN = 177 ; the moves in the lists up to
KEY_DEL = 182
KEY_PGUP = 184 ; here
MB_LEFT = 1 ; held
MB_LEFT_DOWN = 0x100 ; pressed, not held at the last event
MB_RIGHT_DOWN = 0x200
; pusha: where it keeps the registers
PUSHA_EDI = 0
PUSHA_EBX = 16
PUSHA_EDX = 20
PUSHA_ECX = 24
PUSHA_EAX = 28
PUSHA_SIZE = 32
; Buttons
BTN_TAB = 2
BTN_SHUTDOWN = 8 ; ids with bit 3 go to the right
BTN_OWN = 16 ; ids from here on belong to the tab
struct TAB ; a row of `tabs`
caption dw ?
list dw ? ; LIST or 0
activate dw ? ; the tab is opened
draw dw ? ; full redraw of the panel
update dw ? ; new statistics
button dw ? ; edx = button id
mouse dw ?
bar dw ? ; the items of its bottom bar
ends
;-------------------------------------------------------------------------------
tabs:
TAB sz_tab_procs, procs_list, nothing, procs_draw, procs_update, procs_button, list_mouse, procs_bar
TAB sz_tab_perf, 0, nothing, perf_draw, perf_draw, perf_cpuid, get_mouse, perf_bar
TAB sz_tab_disks, disks_list, disks_scan, list_draw, disks_update, disks_open, list_mouse, disks_bar
TAB sz_tab_drivers, drivers_list, drivers_scan, list_draw, nothing, drivers_load, list_mouse, drivers_bar
TAB sz_tab_autorun, autorun_list, autorun_load, list_draw, nothing, autorun_toggle, list_mouse, autorun_bar
NTABS = ($ - tabs) / sizeof.TAB
app_info FileInfoBlock SSF_START_APP, 0, 0, 0, 0, 0, 0 ; the parameters, the path
sz_run_path db "/sys/RUN", 0
sz_end_path db "/sys/END", 0
sz_tinfo_path db "/sys/TINFO", 0
icons_name db "ICONS18", 0
box_lib_path db "/sys/lib/box_lib.obj", 0
align 4
box_lib:
import box_lib, \
scrollbar_v_draw, "scrollbar_v_draw", \
scrollbar_v_mouse, "scrollbar_v_mouse", \
check_box_draw2, "check_box_draw2"
sb scrollbar SB_W - 1, 0, 0, AREA_Y, SB_W - 1, 0, 0, 0, 0, 0, 0, 1 ; the sizes - 1:
; box_lib draws a pixel more
cb check_box2 0, 0, PAD, 0, 0, 0x80000000, cb.size_of_str, 0 ; no text: its length
IncludeUGlobals
align 4
sc system_colors ; the button color: the main one
green dd ? ; of the button: run
red dd ? ; and of high values, end
mid dd ? ; the list header, the scrollbar
pinfo process_information
next_tick dd ?
cur_tab dd ?
buttons dd ? ; mouse buttons held at the last event
area_w dd ? ; panel: x = PAD, y = AREA_Y
area_h dd ?
bar_y dd ? ; bottom bar
bar_left dd ?
bar_right dd ? ; left end of the right buttons
icons dd ? ; ICONS18 or 0
icon_buf rd ICON*ICON
text_buf rb TEXT_CHARS * 4 + 1 ; UTF-8 takes up to 4 bytes
macro max_of name, [value] {
common name = 0
forward
if value > name
name = value
end if
}
max_of TAB_DATA, PROCS_DATA, DISKS_DATA, DRIVERS_DATA, AUTORUN_DATA
align 4
tab_data rb TAB_DATA ; data of the open tab
+240
View File
@@ -0,0 +1,240 @@
; The window: its colors, size and place, the panel and the tabs, then the
; panel of the open tab.
draw_window:
mcall SF_REDRAW, SSF_BEGIN_DRAW
mcall SF_STYLE_SETTINGS, SSF_GET_COLORS, sc, sizeof.system_colors
mov eax, [sc.work_button] ; its channels high to low: al, ah, dl
mov edx, eax
shr edx, 16
cmp al, ah
jae @f
xchg al, ah
@@:
cmp al, dl
jae @f
xchg al, dl
@@:
cmp ah, dl
jae @f
xchg ah, dl
@@:
movzx ecx, dl ; blue, green, red
shl ecx, 16
mov cx, ax
mov [sc.work_button], ecx
mov dl, al ; the low ones half the high one
shr dl, 1
movzx ecx, dl ; all low, then green, red high
imul ecx, 0x10101
mov [green], ecx
mov byte [green + 1], al
mov [red], ecx
mov byte [red + 2], al
mov eax, [sc.work] ; between the window and the panel
mov edx, [sc.work_light]
call mix
mov [mid], eax
mcall SF_GET_SCREEN_SIZE ; half the screen, the kernel takes
shr eax, 1 ; it the first time
xchg esi, eax
mcall SF_STYLE_SETTINGS, SSF_GET_SCREEN_AREA
mov edx, esi
shr edx, 16
mov ebp, MIN_W - 1
call .fit
xchg eax, ebx
movzx edx, si
and dh, 0x7F
mov ebp, MIN_H - 1
call .fit
xchg eax, ecx
mov edx, [sc.work]
or edx, WIN_STYLE
mcall SF_CREATE_WINDOW, , , , 0, sz_title
mcall SF_THREAD_INFO, pinfo, -1
test [pinfo.wnd_state], WND_ROLLED_UP
jnz .done
test [pinfo.wnd_state], WND_MAXIMIZED ; the size it gets
jnz .layout
mov edx, [pinfo.box.width] ; not smaller than the minimum
mov esi, [pinfo.box.height]
cmp edx, MIN_W - 1 ; the kernel keeps the size - 1
jae @f
mov edx, MIN_W - 1
@@:
cmp esi, MIN_H - 1
jae @f
mov esi, MIN_H - 1
@@:
cmp edx, [pinfo.box.width]
jne @f
cmp esi, [pinfo.box.height]
je .layout
@@:
mcall SF_CHANGE_WINDOW, -1, -1 ; it sends a new redraw
jmp .done
.layout:
mov eax, [pinfo.client_box.width]
lea ecx, [eax - PAD*2]
mov [area_w], ecx
mov [bar_right], eax
mov [bar_left], PAD
mov eax, [pinfo.client_box.height]
sub eax, PAD + BTN_H
mov [bar_y], eax
sub eax, AREA_Y + PAD
mov [area_h], eax
mov ebx, PAD shl 16
mov bx, word [area_w]
mov ecx, AREA_Y shl 16
mov cx, ax
mov edx, [sc.work_light]
call frame_rect
mov edx, [sc.work] ; around the tabs and the panel: above,
mov ebx, [area_w] ; below with the bar, left, right
add ebx, 2*PAD + 1
mcall SF_DRAW_RECT, , TOP
mov ecx, [bar_y]
sub ecx, PAD
shl ecx, 16
mov cx, 2*PAD + BTN_H + 1
mcall SF_DRAW_RECT
mov ecx, [area_h]
add ecx, (TOP shl 16) + TAB_H - 1
mov ebx, PAD
mcall SF_DRAW_RECT
mov ebx, [area_w]
add ebx, PAD
shl ebx, 16
mov bx, PAD + 1
mcall SF_DRAW_RECT
mov esi, [area_w] ; the tabs as wide as the panel, the
add esi, NTABS - 1 ; room left shared alike
xor ebp, ebp
@@:
call .content
sub esi, eax
inc ebp
cmp ebp, NTABS
jb @b
xchg eax, esi
xor edx, edx
mov ecx, NTABS
div ecx
xchg eax, esi
mov ebx, PAD shl 16
xor ebp, ebp
.tab:
call .content
add eax, esi
cmp ebp, NTABS - 1 ; the last one to the end of the panel
jne @f
mov eax, [area_w]
add eax, PAD
mov edx, ebx
shr edx, 16
sub eax, edx
@@:
mov bx, ax
call .draw
imul eax, ebx, 1 shl 16
lea ebx, [ebx + eax - 1 shl 16] ; neighbours share the border
inc ebp
cmp ebp, NTABS
jb .tab
mov eax, sz_shutdown ; at the right end
mov edx, BTN_SHUTDOWN
mov esi, [sc.work_graph]
call bar_button
imul esi, [cur_tab], sizeof.TAB ; the bar of the tab, then its
movzx esi, word [tabs + esi + TAB.bar] ; panel
call bar_draw
mov eax, TAB.draw
call tab_call
.done:
mcall SF_REDRAW, SSF_END_DRAW
ret
; eax = start shl 16 + end of the work area, edx = the size - 1 wanted,
; ebp = the least; out: eax = start shl 16 + size - 1 of the window in its
; middle
.fit:
cmp edx, ebp
jae @f
mov edx, ebp
@@:
movzx ecx, ax
shr eax, 16
sub ecx, eax
cmp edx, ecx
jb @f
mov edx, ecx
@@:
sub ecx, edx
shr ecx, 1
add eax, ecx
shl eax, 16
mov ax, dx
ret
.draw: ; the caption in the middle
pusha
mov ecx, (TOP shl 16) + TAB_H
mov esi, [sc.work_dark]
cmp ebp, [cur_tab]
jne @f
mov esi, [sc.work_light]
@@:
mov edx, esi
call frame_rect
lea edx, [ebp + BTN_TAB + BT_HIDE + BT_NOFRAME]
mcall SF_DEFINE_BUTTON
call .content
movzx ecx, bx
sub ecx, eax
shr ecx, 1
shl ecx, 16
add ebx, ecx
mov ecx, TOP shl 16
mov eax, [sc.work_text]
jmp bar_text ; as high as the bar items
; ebp = tab; out: edi -> its caption, eax = its width
.content:
imul edi, ebp, sizeof.TAB
movzx edi, word [tabs + edi + TAB.caption]
mov eax, edi
call text_width
ret