From f7942d2eb3f831afaa0a0120479e03397258f98e Mon Sep 17 00:00:00 2001 From: Ivan Baravy Date: Mon, 12 Oct 2020 06:02:02 +0300 Subject: [PATCH] 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. --- .gitignore | 1 + README | 47 ++++++++++++---- makefile | 13 +---- shell.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++ tools/lfbviewx.c | 81 +++++++++++++++++++++++++++ tools/makefile | 24 ++++++++ umka.asm | 32 +++++++---- umka.h | 44 +++++++++++++-- umka_os.c | 11 +++- 9 files changed, 357 insertions(+), 37 deletions(-) create mode 100644 tools/lfbviewx.c create mode 100644 tools/makefile diff --git a/.gitignore b/.gitignore index 920372e..5113412 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ umka_os umka_ping mkdirrange mkfilepattern +lfbviewx *.img *.img.xz *.img.gz diff --git a/README b/README index e00a618..7b37e03 100644 --- a/README +++ b/README @@ -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 diff --git a/makefile b/makefile index 284cc03..52832eb 100644 --- a/makefile +++ b/makefile @@ -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 diff --git a/shell.c b/shell.c index be1dadd..2066835 100644 --- a/shell.c +++ b/shell.c @@ -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 {+|-|=}]" + "[-y {+|-|=}] [-h {+|-}] [-v {+|-}]\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 }, }; diff --git a/tools/lfbviewx.c b/tools/lfbviewx.c new file mode 100644 index 0000000..fdba927 --- /dev/null +++ b/tools/lfbviewx.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + if (argc != 5) { + printf("usage: lfbviewx
\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; +} diff --git a/tools/makefile b/tools/makefile new file mode 100644 index 0000000..3cc1f9d --- /dev/null +++ b/tools/makefile @@ -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 diff --git a/umka.asm b/umka.asm index bec9e79..cb7f706 100644 --- a/umka.asm +++ b/umka.asm @@ -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 diff --git a/umka.h b/umka.h index 61ec51e..cbd20c5 100644 --- a/umka.h +++ b/umka.h @@ -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); diff --git a/umka_os.c b/umka_os.c index b752136..1969558 100644 --- a/umka_os.c +++ b/umka_os.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -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();