New tool lfbviewx, new shell commands, fix bug in process_info(-1).

* lfbviewx: LFB viewer for X. Reads framebuffer of umka_os and displays
  the picture in X window.
* New shell commands: dump_appdata, dump_taskdata, mouse_move.
* Bug with process_info is because SLOT_BASE in umka_os is not aligned
  on 0x10000. Mitigated with a macro.
This commit is contained in:
Ivan Baravy 2020-10-12 06:02:02 +03:00
parent 477978175d
commit f7942d2eb3
9 changed files with 357 additions and 37 deletions

1
.gitignore vendored
View File

@ -8,6 +8,7 @@ umka_os
umka_ping
mkdirrange
mkfilepattern
lfbviewx
*.img
*.img.xz
*.img.gz

47
README
View File

@ -2,26 +2,52 @@ UMKa -- User-Mode KolibriOS developer tools
===========================================
This is a common project for a set of KolibriOS developer tools which are based
on original KolibriOS code wrapped and hacked as to run in the UNIX programming
environment. The idea is to make userspace UNIX tools that use as much unchanged
KolibriOS source as possible to test architecture-independent parts of the
kernel in your favorite developer environment.
on original KolibriOS kernel code wrapped and hacked as to run in the UNIX
programming environment. The idea is to make userspace UNIX tools that use as
much unchanged KolibriOS kernel source as possible to test
architecture-independent parts of the kernel in your favorite developer
environment.
umka_shell
----------
is an interactive shell with commands that are wrappers around KolibriOS kernel
block, FS, UI and other functions. Can read input from the keyboard, stdin and a
file, i.e. can be used for automated testing.
syscalls and other internal functions. What works now: block layer including
disk cache, FS, UI and graphics, scheduler, ACPI/AML interpreter,
synchronization primitives, strings, slab allocator, events, unpacker, other
minor functions.
It can also be used for automated testing by feeding it a file of commands
instead of typing them.
Example:
$ umka_shell < mytest.t > mytest.out.log
umka_fuse
---------
is like umka_shell above but commands are translated from FUSE calls, not
entered manually. Can *potentially* be used to run xfstests (cross-fs-tests) and
automatestrcatd tests against reference FS implementations.
entered manually or read from a file. Can *potentially* be used to run xfstests
(cross-fs-tests) and automated tests against reference FS implementation.
umka_os
-------
is KolibriOS kernel running main loop (osloop), scheduler and all the threads
including network stack.
tools
-----
mkdirrange
mkfilepattern
lfbviewx
BUILD
@ -43,13 +69,14 @@ Framebuffer can be dumped to disk as image file.
Testing
-------
sudo cp --parents --no-preserve=mode /sys/firmware/acpi/tables/?SDT* /sys/bus/pci/devices/*/config .
sudo cp --parents /sys/firmware/acpi/tables/?SDT* /sys/bus/pci/devices/*/config .
Troubleshooting
---------------
No troubles -- no shooting.
# sysctl -w kernel.yama.ptrace_scope=0
# sysctl -w vm.mmap_min_addr=0
Links & Acknowledgements

View File

@ -12,7 +12,7 @@ LDFLAGS=-no-pie
LDFLAGS_32=$(LDFLAGS) -m32
all: umka_shell umka_fuse umka_os umka_ping umka.sym umka.prp umka.lst tags \
tools/mkdirrange tools/mkfilepattern covpreproc default.skn skin.skn
covpreproc default.skn skin.skn
covpreproc: covpreproc.c
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
@ -85,20 +85,13 @@ umka_fuse.o: umka_fuse.c umka.h
$(CC) $(CFLAGS_32) `pkg-config fuse3 --cflags` -c $<
umka_os.o: umka_os.c umka.h
$(CC) $(CFLAGS_32) -c $<
$(CC) $(CFLAGS_32) -c $< -D_DEFAULT_SOURCE
umka_ping.o: umka_ping.c umka.h
$(CC) $(CFLAGS_32) -D_DEFAULT_SOURCE -c $<
tools/mkdirrange: tools/mkdirrange.c
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
tools/mkfilepattern: tools/mkfilepattern.c
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
.PHONY: all clean
clean:
rm -f *.o umka_shell umka_fuse umka_os umka.fas umka.sym umka.lst umka.prp \
coverage tools/mkdirrange tools/mkfilepattern
coverage

141
shell.c
View File

@ -443,6 +443,144 @@ void shell_dump_win_pos(int argc, char **argv) {
}
}
void shell_dump_appdata(int argc, char **argv) {
// TODO: usage
int idx;
int show_pointers = 0;
if (argc > 1) {
idx = strtol(argv[1], NULL, 0);
}
if (argc > 2 && !strcmp(argv[2], "-p")) {
show_pointers = 1;
}
appdata_t *a = kos_slot_base + idx;
fprintf(fout, "app_name: %s\n", a->app_name);
if (show_pointers) {
fprintf(fout, "process: %p\n", (void*)a->process);
fprintf(fout, "fpu_state: %p\n", (void*)a->fpu_state);
fprintf(fout, "exc_handler: %p\n", (void*)a->exc_handler);
}
fprintf(fout, "except_mask: %" PRIx32 "\n", a->except_mask);
if (show_pointers) {
fprintf(fout, "pl0_stack: %p\n", (void*)a->pl0_stack);
fprintf(fout, "cursor: %p\n", (void*)a->cursor);
fprintf(fout, "fd_ev: %p\n", (void*)a->fd_ev);
fprintf(fout, "bk_ev: %p\n", (void*)a->bk_ev);
fprintf(fout, "fd_obj: %p\n", (void*)a->fd_obj);
fprintf(fout, "bk_obj: %p\n", (void*)a->bk_obj);
fprintf(fout, "saved_esp: %p\n", (void*)a->saved_esp);
}
fprintf(fout, "dbg_state: %u\n", a->dbg_state);
fprintf(fout, "cur_dir: %s\n", a->cur_dir);
fprintf(fout, "event_filter: %" PRIx32 "\n", a->event_filter);
fprintf(fout, "draw_bgr_x: %u\n", a->draw_bgr_x);
fprintf(fout, "draw_bgr_y: %u\n", a->draw_bgr_y);
fprintf(fout, "event_mask: %" PRIx32 "\n", a->event_mask);
fprintf(fout, "terminate_protection: %u\n", a->terminate_protection);
fprintf(fout, "keyboard_mode: %u\n", a->keyboard_mode);
fprintf(fout, "captionEncoding: %u\n", a->captionEncoding);
fprintf(fout, "exec_params: %s\n", a->exec_params);
fprintf(fout, "wnd_caption: %s\n", a->wnd_caption);
fprintf(fout, "wnd_clientbox (ltwh): %u %u %u %u\n", a->wnd_clientbox.left,
a->wnd_clientbox.top, a->wnd_clientbox.width,
a->wnd_clientbox.height);
fprintf(fout, "priority: %u\n", a->priority);
}
void shell_dump_taskdata(int argc, char **argv) {
// TODO: usage
int idx;
if (argc > 1) {
idx = strtol(argv[1], NULL, 0);
}
taskdata_t *t = kos_task_base + idx;
fprintf(fout, "event_mask: %" PRIx32 "\n", t->event_mask);
}
void shell_mouse_move(int argc, char **argv) {
const char *usage = \
"usage: mouse_move [-l] [-m] [-r] [-x {+|-|=}<value>]"
"[-y {+|-|=}<value>] [-h {+|-}<value>] [-v {+|-}<value>]\n"
" -l left button is held\n"
" -m middle button is held\n"
" -r right button is held\n"
" -x increase, decrease or set x coordinate\n"
" -y increase, decrease or set y coordinate\n"
" -h scroll horizontally\n"
" -v scroll vertically\n";
int lbheld = 0, mbheld = 0, rbheld = 0, xabs = 0, yabs = 0;
int32_t xmoving = 0, ymoving = 0, hscroll = 0, vscroll = 0;
int opt;
optind = 1;
while ((opt = getopt(argc, argv, "lmrx:y:h:v:")) != -1) {
switch (opt) {
case 'l':
lbheld = 1;
break;
case 'm':
mbheld = 1;
break;
case 'r':
rbheld = 1;
break;
case 'x':
switch (*optarg++) {
case '=':
xabs = 1;
__attribute__ ((fallthrough));
case '+':
xmoving = strtol(optarg, NULL, 0);
break;
case '-':
xmoving = -strtol(optarg, NULL, 0);
break;
default:
fputs(usage, fout);
return;
}
break;
case 'y':
switch (*optarg++) {
case '=':
yabs = 1;
__attribute__ ((fallthrough));
case '+':
ymoving = strtol(optarg, NULL, 0);
break;
case '-':
ymoving = -strtol(optarg, NULL, 0);
break;
default:
fputs(usage, fout);
return;
}
break;
case 'h':
if ((optarg[0] != '+') && (optarg[0] != '-')) {
fputs(usage, fout);
return;
}
hscroll = strtol(optarg, NULL, 0);
break;
case 'v':
if ((optarg[0] != '+') && (optarg[0] != '-')) {
fputs(usage, fout);
return;
}
vscroll = strtol(optarg, NULL, 0);
break;
default:
fputs(usage, fout);
return;
}
}
COVERAGE_ON();
umka_mouse_move(lbheld, mbheld, rbheld, xabs, xmoving, yabs, ymoving,
hscroll, vscroll);
COVERAGE_OFF();
}
void shell_process_info(int argc, char **argv) {
(void)argc;
process_information_t info;
@ -1941,6 +2079,8 @@ func_table_t funcs[] = {
{ "scrot", shell_scrot },
{ "dump_win_stack", shell_dump_win_stack },
{ "dump_win_pos", shell_dump_win_pos },
{ "dump_appdata", shell_dump_appdata },
{ "dump_taskdata", shell_dump_taskdata },
{ "acpi_set_usage", shell_acpi_set_usage },
{ "acpi_get_usage", shell_acpi_get_usage },
{ "acpi_enable", shell_acpi_enable },
@ -1987,6 +2127,7 @@ func_table_t funcs[] = {
{ "bg_unmap", shell_bg_unmap },
{ "pci_set_path", shell_pci_set_path },
{ "pci_get_path", shell_pci_get_path },
{ "mouse_move", shell_mouse_move },
{ NULL, NULL },
};

81
tools/lfbviewx.c Normal file
View File

@ -0,0 +1,81 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/uio.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/XKBlib.h>
int main(int argc, char *argv[]) {
if (argc != 5) {
printf("usage: lfbviewx <pid> <address> <width> <height>\n");
exit(1);
}
int depth = 32;
int umka_pid = strtol(argv[1], NULL, 0);
uintptr_t umka_lfb_addr = strtol(argv[2], NULL, 0);
size_t lfb_width = strtoul(argv[3], NULL, 0);
size_t lfb_height = strtoul(argv[4], NULL, 0);
Display *display = XOpenDisplay(NULL);
int screen_num = XDefaultScreen(display);
Window root = XDefaultRootWindow(display);
XVisualInfo vis_info;
if(!XMatchVisualInfo(display, screen_num, depth, TrueColor, &vis_info)) {
fprintf(stderr, "ERR: %d-bit depth is not supported\n", depth);
exit(1);
}
Visual *visual = vis_info.visual;
XSetWindowAttributes win_attr = {
.colormap = XCreateColormap(display, root, visual, AllocNone),
.background_pixel = 0,
.border_pixel = 0};
unsigned long win_mask = CWBackPixel | CWColormap | CWBorderPixel;
Window window = XCreateWindow(display, root, 0, 0, lfb_width, lfb_height, 0, depth, InputOutput, visual, win_mask, &win_attr);
GC gc = XCreateGC(display, window, 0, 0);
uint32_t *lfb = (uint32_t*)malloc(lfb_width*lfb_height*sizeof(uint32_t));
XImage *image = XCreateImage(display, visual, depth, ZPixmap, 0, (char*)lfb, lfb_width, lfb_height, 32, 0);
XSelectInput(display, window, ExposureMask | KeyPressMask);
XStoreName(display, window, "KolibriOS LFB Viewer for X");
XMapWindow(display, window);
struct iovec remote = {.iov_base = (void*)umka_lfb_addr,
.iov_len = lfb_width*lfb_height*4};
struct iovec local = {.iov_base = lfb,
.iov_len = lfb_width*lfb_height*4};
/*
XEvent event;
while (true) {
XNextEvent(display, &event);
if (event.type == Expose) {
process_vm_readv(umka_pid, &local, 1, &remote, 1, 0);
XPutImage(display, window, gc, image, 0, 0, 0, 0, lfb_width, lfb_height);
} else if (event.type == KeyPress) {
int keysym = XkbKeycodeToKeysym(display, event. xkey.keycode, 0, 0);
if (keysym == XK_Escape) break;
switch (keysym) {
case XK_Left: {break;}
}
}
}
*/
XEvent event;
while (true) {
while (XCheckMaskEvent(display, (long)-1, &event)) { /* skip */ }
process_vm_readv(umka_pid, &local, 1, &remote, 1, 0);
XPutImage(display, window, gc, image, 0, 0, 0, 0, lfb_width, lfb_height);
sleep(1);
}
XCloseDisplay(display);
return 0;
}

24
tools/makefile Normal file
View File

@ -0,0 +1,24 @@
CC=gcc
WARNINGS=-Wall -Wextra -Wduplicated-cond -Wduplicated-branches -Wlogical-op \
-Wrestrict -Wnull-dereference -Wjump-misses-init -Wshadow -Wformat=2 \
-Wswitch -Wswitch-enum -Wpedantic
NOWARNINGS=-Wno-address-of-packed-member
CFLAGS=$(WARNINGS) $(NOWARNINGS) -std=c11 -O2 \
-DNDEBUG -D_POSIX_C_SOURCE=200809L -fno-pie
LDFLAGS=-no-pie
all: mkdirrange mkfilepattern lfbviewx
mkdirrange: mkdirrange.c
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
mkfilepattern: mkfilepattern.c
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
lfbviewx: lfbviewx.c
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -lX11 -lXext -D_GNU_SOURCE
.PHONY: all clean
clean:
rm -f *.o mkdirrange mkfilepattern lfbviewx

View File

@ -30,7 +30,6 @@ public sha3_256_oneshot as 'hash_oneshot'
public kos_time_to_epoch
public kos_init
public monitor_thread
public CURRENT_TASK as 'kos_current_task'
public current_slot as 'kos_current_slot'
public TASK_COUNT as 'kos_task_count'
@ -64,6 +63,7 @@ public REDRAW_BACKGROUND
public scheduler_add_thread
public new_sys_threads
public osloop
public set_mouse_data as 'kos_set_mouse_data'
macro cli {
pushfd
@ -193,8 +193,19 @@ macro call target {
}
do_change_task equ hjk
irq0 equ jhg
macro mov r, v {
if r eq [CURRENT_TASK] & v eq bh
push ebx
sub ebx, SLOT_BASE
mov [CURRENT_TASK], bh
pop ebx
else
mov r, v
end if
}
include 'core/sched.inc'
restore do_change_task
purge mov
purge call
restore irq0
include 'core/syscall.inc'
;include 'core/fpu.inc'
@ -423,7 +434,7 @@ proc kos_init c uses ebx esi edi ebp
mov dword[CURRENT_TASK], 2
mov dword[TASK_COUNT], 2
mov dword[TASK_BASE], CURRENT_TASK + 2*sizeof.TASKDATA
mov [current_slot], SLOT_BASE+256*2
mov [current_slot], SLOT_BASE+2*sizeof.APPDATA
mov [CURRENT_TASK + 2*sizeof.TASKDATA + TASKDATA.pid], 2
call set_window_defaults
@ -431,8 +442,8 @@ proc kos_init c uses ebx esi edi ebp
call calculatebackground
call init_display
mov eax, [def_cursor]
mov [SLOT_BASE+APPDATA.cursor+256], eax
mov [SLOT_BASE+APPDATA.cursor+256*2], eax
mov [SLOT_BASE+APPDATA.cursor+sizeof.APPDATA], eax
mov [SLOT_BASE+APPDATA.cursor+sizeof.APPDATA*2], eax
; from set_variables
xor eax, eax
@ -440,7 +451,7 @@ proc kos_init c uses ebx esi edi ebp
mov byte [KEY_COUNT], al ; keyboard buffer
mov byte [BTN_COUNT], al ; button buffer
mov ebx, SLOT_BASE + 2*256
mov ebx, SLOT_BASE + 2*sizeof.APPDATA
mov word[cur_dir.path], '/'
mov [ebx+APPDATA.cur_dir], cur_dir
@ -501,7 +512,6 @@ proc delay_ms
ret
endp
extrn reset_procmask
extrn get_fake_if
extrn restart_timer
@ -518,7 +528,7 @@ proc irq0 c, _signo, _info, _context
mov bl, SCHEDULE_ANY_PRIORITY
call find_next_task
jz .done ; if there is only one running process
call do_change_task
call _do_change_task
.done:
ccall restart_timer
popad
@ -644,13 +654,11 @@ purge sys_msg_board,HEAP_BASE,__pew8
coverage_end:
section '.data' writeable align 64
section '.data' writeable align 4096
public umka_tool
umka_tool dd ?
fpu_owner dd ?
monitor_thread dd ?
uglobal
v86_irqhooks rd IRQ_RESERVED*2
cache_ide0 IDE_CACHE
@ -685,7 +693,9 @@ WIN_POS rw 0x600
rb 0x1000000
BOOT_LO boot_data
BOOT boot_data
align 4096
lfb_base rd MAX_SCREEN_WIDTH*MAX_SCREEN_HEIGHT
align 4096
cur_dir:
.encoding rb 1
.path rb maxPathLength

44
umka.h
View File

@ -336,7 +336,7 @@ uint32_t kos_time_to_epoch(uint32_t *time);
disk_t *disk_add(diskfunc_t *disk, const char *name, void *userdata, uint32_t flags) __attribute__((__stdcall__));
void *disk_media_changed(diskfunc_t *disk, int inserted) __attribute__((__stdcall__));
void disk_del(disk_t *disk) __attribute__((__stdcall__));
void disk_del(disk_t *disk) __attribute__((__stdcall__));
void hash_oneshot(void *ctx, void *data, size_t len);
@ -348,6 +348,19 @@ extern uint8_t ntfs_user_functions[];
extern uint8_t kos_ramdisk[2880*512];
disk_t *kos_ramdisk_init(void);
void kos_set_mouse_data(uint32_t btn_state, int32_t xmoving, int32_t ymoving,
int32_t vscroll, int32_t hscroll)
__attribute__((__stdcall__));
static inline void umka_mouse_move(int lbheld, int mbheld, int rbheld,
int xabs, int32_t xmoving,
int yabs, int32_t ymoving,
int32_t hscroll, int32_t vscroll) {
uint32_t btn_state = lbheld + (rbheld << 1) + (mbheld << 2) +
(yabs << 30) + (xabs << 31);
kos_set_mouse_data(btn_state, xmoving, ymoving, vscroll, hscroll);
}
static inline void umka_new_sys_threads(uint32_t flags, void (*entry)(), void *stack) {
__asm__ __inline__ __volatile__ (
"pushad;"
@ -438,13 +451,35 @@ typedef struct {
uint32_t pad[5];
} event_t;
typedef struct {
lhead_t list;
lhead_t thr_list;
mutex_t heap_lock;
void *heap_base;
void *heap_top;
uint32_t mem_used;
void *dlls_list_ptr;
void *pdt_0_phys;
void *pdt_1_phys;
void *io_map_0;
void *io_map_1;
void *ht_lock;
void *ht_free;
void *ht_next;
void *htab[(1024-18*4)/4];
void *pdt_0[1024];
} proc_t;
_Static_assert(sizeof(proc_t) == 0x1400, "must be 0x1400 bytes long");
typedef struct {
char app_name[11];
uint8_t pad1[5];
lhead_t list; // +16
uint32_t process; // +24
sigjmp_buf *fpu_state; // +28
proc_t *process; // +24
void *fpu_state; // +28
void *exc_handler; // +32
uint32_t except_mask; // +36
void *pl0_stack; // +40
@ -453,7 +488,7 @@ typedef struct {
event_t *bk_ev; // +52
appobj_t *fd_obj; // +56
appobj_t *bk_obj; // +60
uint32_t saved_esp; // +64
void *saved_esp; // +64
uint32_t io_map[2]; // +68
uint32_t dbg_state; // +76
char *cur_dir; // +80
@ -521,7 +556,6 @@ extern size_t kos_task_count;
extern taskdata_t *kos_task_base;
extern taskdata_t kos_task_data[];
extern appdata_t kos_slot_base[];
extern void (*monitor_thread)(void);
extern void umka_do_change_task(appdata_t *new);
extern void scheduler_add_thread(void);
extern void find_next_task(void);

View File

@ -2,6 +2,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
@ -37,7 +38,15 @@ int main() {
return 1;
}
monitor_thread = monitor;
/*
void *app_base = mmap((void*)0x000000, 16*0x100000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (app_base == MAP_FAILED) {
perror("mmap failed");
exit(1);
}
*/
printf("pid=%d, kos_lfb_base=%p\n", getpid(), (void*)kos_lfb_base);
kos_init();
kos_stack_init();