From 695179374324b830347630283dd6ba1556314c92 Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Thu, 28 Mar 2024 08:36:05 -0600 Subject: [PATCH 1/2] [kernel] Dynamically allocate task array First step, allocate fixed size array --- elks/arch/i86/boot/crt0.S | 7 +++--- elks/arch/i86/kernel/irqtab.S | 12 ++++++++-- elks/include/linuxmt/sched.h | 4 +++- elks/init/main.c | 42 +++++++++++++++++++++-------------- elks/kernel/fork.c | 2 +- elks/kernel/sched.c | 6 +++-- 6 files changed, 46 insertions(+), 27 deletions(-) diff --git a/elks/arch/i86/boot/crt0.S b/elks/arch/i86/boot/crt0.S index eaba22eaa..73a07b53a 100644 --- a/elks/arch/i86/boot/crt0.S +++ b/elks/arch/i86/boot/crt0.S @@ -1,5 +1,4 @@ #include -#include // Assembler boot strap hooks. This is called by setup @@ -42,11 +41,11 @@ _start: mov %cs,kernel_cs mov %ds,kernel_ds -// Set SS:SP to task[0] kernel stack area +// Set SS:SP to kernel interrupt stack for temporary use mov %ds,%ax mov %ax,%ss // SS=ES=DS - mov $task + TASK_USER_AX,%sp + mov $istack,%sp call start_kernel // fall through into breakpoint if returns @@ -81,7 +80,7 @@ early_putchar: .global _endbss .extern kernel_cs .extern kernel_ds - .extern task + .extern istack _endtext: .word 0 diff --git a/elks/arch/i86/kernel/irqtab.S b/elks/arch/i86/kernel/irqtab.S index 5a0e151b2..571a71c62 100644 --- a/elks/arch/i86/kernel/irqtab.S +++ b/elks/arch/i86/kernel/irqtab.S @@ -362,9 +362,9 @@ restore_regs: iret /* - * tswitch(); + * tswitch() * - * This function can only be called with SS=DS=ES=kernel DS and + * This function can only be called with SS=DS=kernel DS and * CS=kernel CS. SS:SP is the relevant kernel stack. Thus we don't need * to arse about with segment registers. The kernel isn't relocating. * @@ -389,6 +389,13 @@ tswitch: pop %bp // BP of schedule() ret +// setsp(void *sp) - set stack pointer + .global setsp +setsp: + pop %bx // return address + pop %ax + mov %ax,%sp + jmp *%bx // Halt - wait for next interrupt to save CPU power .global idle_halt @@ -399,6 +406,7 @@ idle_halt: .data .global intr_count .global endistack + .global istack .extern current .extern previous diff --git a/elks/include/linuxmt/sched.h b/elks/include/linuxmt/sched.h index f0ed6d95e..ad0a12564 100644 --- a/elks/include/linuxmt/sched.h +++ b/elks/include/linuxmt/sched.h @@ -110,7 +110,8 @@ struct task_struct { /* We use typedefs to avoid using struct foobar (*) */ typedef struct task_struct __task, *__ptask; -extern __task task[MAX_TASKS]; +extern __task *task; +extern __task *next_task_slot; extern volatile jiff_t jiffies; /* ticks updated by the timer interrupt*/ extern __ptask current; @@ -168,6 +169,7 @@ extern unsigned int get_ustack(struct task_struct *,int); extern void put_ustack(register struct task_struct *,int,int); extern void tswitch(void); +extern void setsp(void *); extern int run_init_process(const char *cmd); extern int run_init_process_sptr(const char *cmd, char *sptr, int slen); extern void ret_from_syscall(void); diff --git a/elks/init/main.c b/elks/init/main.c index d245c112c..412ad5478 100644 --- a/elks/init/main.c +++ b/elks/init/main.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,7 @@ __u16 kernel_cs, kernel_ds; int tracing; int nr_ext_bufs, nr_xms_bufs, nr_map_bufs; static int boot_console; +static seg_t membase, memend; static char bininit[] = "/bin/init"; static char binshell[] = "/bin/sh"; #ifdef CONFIG_SYS_NO_BININIT @@ -57,6 +59,7 @@ static char *init_command = bininit; /* * Parse /bootopts startup options */ +static char opts; static int args = 2; /* room for argc and av[0] */ static int envs; static int argv_slen; @@ -82,11 +85,17 @@ static char * INITPROC option(char *s); static void init_task(void); static void INITPROC kernel_banner(seg_t start, seg_t end, seg_t init, seg_t extra); +static void INITPROC early_kernel_init(void); - +/* this procedure called using temp stack then switched, no temp vars allowed */ void start_kernel(void) { - kernel_init(); + early_kernel_init(); /* read bootopts using kernel interrupt stack */ + task = heap_alloc(MAX_TASKS * sizeof(struct task_struct), + HEAP_TAG_INTHAND|HEAP_TAG_CLEAR); + if (!task) for(;;) ; + setsp(&task->t_regs.ax); /* change to idle task stack */ + kernel_init(); /* continue init running on idle task stack */ /* fork and run procedure init_task() as task #1*/ kfork_proc(init_task); @@ -105,25 +114,24 @@ void start_kernel(void) } } -void INITPROC kernel_init(void) +static void INITPROC early_kernel_init(void) { - seg_t base, end; - - /* sched_init sets us (the current stack) to be idle task #0*/ - sched_init(); - setup_arch(&base, &end); - mm_init(base, end); - irq_init(); - tty_init(); - + setup_arch(&membase, &memend); /* initializes kernel heap */ + mm_init(membase, memend); /* parse_options may call seg_add */ + tty_init(); /* parse_options may call rs_setbaud */ #ifdef CONFIG_TIME_TZ - tz_init(CONFIG_TIME_TZ); + tz_init(CONFIG_TIME_TZ); /* parse_options may call tz_init */ #endif - #ifdef CONFIG_BOOTOPTS - /* parse options found in /bootops */ - int opts = parse_options(); + opts = parse_options(); /* parse options found in /bootops */ #endif +} + +void INITPROC kernel_init(void) +{ + /* set us (the current stack) to be idle task #0*/ + sched_init(); + irq_init(); /* set console from /bootopts console= or 0=default*/ set_console(boot_console); @@ -163,7 +171,7 @@ void INITPROC kernel_init(void) seg_t s = 0, e = 0; #endif - kernel_banner(base, end, s, e - s); + kernel_banner(membase, memend, s, e - s); } static void INITPROC kernel_banner(seg_t start, seg_t end, seg_t init, seg_t extra) diff --git a/elks/kernel/fork.c b/elks/kernel/fork.c index b13d81e1c..8afc96ef1 100644 --- a/elks/kernel/fork.c +++ b/elks/kernel/fork.c @@ -9,7 +9,7 @@ #include int task_slots_unused = MAX_TASKS; -struct task_struct *next_task_slot = task; +__task *next_task_slot; pid_t last_pid = -1; static pid_t get_pid(void) diff --git a/elks/kernel/sched.c b/elks/kernel/sched.c index fe2d5202f..49415ed87 100644 --- a/elks/kernel/sched.c +++ b/elks/kernel/sched.c @@ -17,8 +17,8 @@ #define idle_task task[0] -__task task[MAX_TASKS]; -__ptask current = task; +__task *task; /* dynamically allocated task array */ +__ptask current; __ptask previous; extern int intr_count; @@ -201,6 +201,8 @@ void INITPROC sched_init(void) (--t)->state = TASK_UNUSED; } while (t > task); + current = task; + next_task_slot = task; /* * Now create task 0 to be ourself. */ From 9adb8998960fd6bfef8dd3349ff7ec068475e248 Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Thu, 28 Mar 2024 09:58:54 -0600 Subject: [PATCH 2/2] Change MAX_TASKS to variable max_tasks Rewrite ps and memoinfo to handle variable sized task array Adjust SETUP_HEAPSIZE for minimal systems --- elks/arch/i86/drivers/char/mem.c | 3 +++ elks/fs/exec.c | 2 +- elks/fs/namei.c | 2 +- elks/include/linuxmt/config.h | 7 +++--- elks/include/linuxmt/heap.h | 2 +- elks/include/linuxmt/mem.h | 1 + elks/include/linuxmt/sched.h | 4 +++- elks/init/main.c | 10 ++++++--- elks/kernel/exit.c | 3 --- elks/kernel/fork.c | 6 ++--- elks/kernel/sched.c | 6 +++-- elkscmd/rootfs_template/bootopts | 5 +++-- elkscmd/sys_utils/meminfo.c | 38 +++++++++++++++++++++----------- elkscmd/sys_utils/ps.c | 9 +++++--- 14 files changed, 62 insertions(+), 36 deletions(-) diff --git a/elks/arch/i86/drivers/char/mem.c b/elks/arch/i86/drivers/char/mem.c index 336a3ef71..4f013c66c 100644 --- a/elks/arch/i86/drivers/char/mem.c +++ b/elks/arch/i86/drivers/char/mem.c @@ -230,6 +230,9 @@ int kmem_ioctl(struct inode *inode, struct file *file, int cmd, char *arg) case MEM_GETTASK: retword = (unsigned short)task; break; + case MEM_GETMAXTASKS: + retword = max_tasks; + break; case MEM_GETCS: retword = kernel_cs; break; diff --git a/elks/fs/exec.c b/elks/fs/exec.c index 4dfeab1de..f2d110d88 100644 --- a/elks/fs/exec.c +++ b/elks/fs/exec.c @@ -161,7 +161,7 @@ int sys_execve(const char *filename, char *sptr, size_t slen) seg_code = currentp->mm.seg_code; break; } - } while (++currentp < &task[MAX_TASKS]); + } while (++currentp < &task[max_tasks]); /* Read the header */ currentp = current; diff --git a/elks/fs/namei.c b/elks/fs/namei.c index 5e00a5937..a594256a0 100644 --- a/elks/fs/namei.c +++ b/elks/fs/namei.c @@ -42,7 +42,7 @@ int permission(register struct inode *inode, int mask) do { if (p->state <= TASK_STOPPED && (p->t_inode == inode)) return -EBUSY; - } while (++p < &task[MAX_TASKS]); + } while (++p < &task[max_tasks]); } if ((mask & MAY_WRITE) && IS_RDONLY(inode) && !S_ISCHR(inode->i_mode) && !S_ISBLK(inode->i_mode)) /* allow writable devices*/ diff --git a/elks/include/linuxmt/config.h b/elks/include/linuxmt/config.h index 760cc7b21..cd73ec936 100644 --- a/elks/include/linuxmt/config.h +++ b/elks/include/linuxmt/config.h @@ -30,11 +30,12 @@ #define UTS_MACHINE "ibmpc i8086" /* The following can be set for minimal systems or for QEMU emulation testing: - * 10 buffers (@20 = 200), 2 ttyq (@80 = 160), 4k L1 cache, 512 heap free = ~4968. - * Use buf=10 cache=4 in /bootopts + * 10 buffers (@20 = 200), 2 ttyq (@80 = 160), 4k L1 cache, 512 heap free, + * 10 tasks (@876 = 8760) = ~13728. + * Use buf=10 cache=4 task=10 in /bootopts */ #if defined(CONFIG_HW_MK88) -#define SETUP_HEAPSIZE 4968 /* force kernel heap size */ +#define SETUP_HEAPSIZE 13728 /* force kernel heap size */ #endif //#undef SETUP_MEM_KBYTES //#define SETUP_MEM_KBYTES 256 /* force available memory in 1K bytes */ diff --git a/elks/include/linuxmt/heap.h b/elks/include/linuxmt/heap.h index 8107a14a1..3ab151bca 100644 --- a/elks/include/linuxmt/heap.h +++ b/elks/include/linuxmt/heap.h @@ -18,7 +18,7 @@ #define HEAP_TAG_SEG 0x01 #define HEAP_TAG_BUF 0x02 #define HEAP_TAG_TTY 0x03 -#define HEAP_TAG_INTHAND 0x04 /* unused */ +#define HEAP_TAG_TASK 0x04 #define HEAP_TAG_BUFHEAD 0x05 #define HEAP_TAG_PIPE 0x06 diff --git a/elks/include/linuxmt/mem.h b/elks/include/linuxmt/mem.h index 8405255d0..5c48735e8 100644 --- a/elks/include/linuxmt/mem.h +++ b/elks/include/linuxmt/mem.h @@ -9,6 +9,7 @@ #define MEM_GETHEAP 7 #define MEM_GETUPTIME 8 #define MEM_GETFARTEXT 9 +#define MEM_GETMAXTASKS 10 struct mem_usage { unsigned int free_memory; diff --git a/elks/include/linuxmt/sched.h b/elks/include/linuxmt/sched.h index ad0a12564..c8263a591 100644 --- a/elks/include/linuxmt/sched.h +++ b/elks/include/linuxmt/sched.h @@ -112,6 +112,8 @@ typedef struct task_struct __task, *__ptask; extern __task *task; extern __task *next_task_slot; +extern int max_tasks; +extern int task_slots_unused; extern volatile jiff_t jiffies; /* ticks updated by the timer interrupt*/ extern __ptask current; @@ -126,7 +128,7 @@ extern time_t current_time(void); #define time_after(a,b) (((long)(b) - (long)(a) < 0)) #define for_each_task(p) \ - for (p = &task[0] ; p!=&task[MAX_TASKS]; p++ ) + for (p = &task[0] ; p!=&task[max_tasks]; p++ ) /* Scheduling and sleeping function prototypes */ diff --git a/elks/init/main.c b/elks/init/main.c index 412ad5478..922063f17 100644 --- a/elks/init/main.c +++ b/elks/init/main.c @@ -91,9 +91,9 @@ static void INITPROC early_kernel_init(void); void start_kernel(void) { early_kernel_init(); /* read bootopts using kernel interrupt stack */ - task = heap_alloc(MAX_TASKS * sizeof(struct task_struct), - HEAP_TAG_INTHAND|HEAP_TAG_CLEAR); - if (!task) for(;;) ; + task = heap_alloc(max_tasks * sizeof(struct task_struct), + HEAP_TAG_TASK|HEAP_TAG_CLEAR); + if (!task) panic("No task mem"); setsp(&task->t_regs.ax); /* change to idle task stack */ kernel_init(); /* continue init running on idle task stack */ @@ -489,6 +489,10 @@ static int INITPROC parse_options(void) nr_map_bufs = (int)simple_strtol(line+6, 10); continue; } + if (!strncmp(line,"task=",5)) { + max_tasks = (int)simple_strtol(line+5, 10); + continue; + } if (!strncmp(line,"comirq=",7)) { comirq(line+7); continue; diff --git a/elks/kernel/exit.c b/elks/kernel/exit.c index 9791ca043..cc56b057a 100644 --- a/elks/kernel/exit.c +++ b/elks/kernel/exit.c @@ -9,9 +9,6 @@ #include #include -extern int task_slots_unused; -extern struct task_struct *next_task_slot; - static void reparent_children(void) { register struct task_struct *p; diff --git a/elks/kernel/fork.c b/elks/kernel/fork.c index 8afc96ef1..fe91f996b 100644 --- a/elks/kernel/fork.c +++ b/elks/kernel/fork.c @@ -8,7 +8,7 @@ #include -int task_slots_unused = MAX_TASKS; +int task_slots_unused; __task *next_task_slot; pid_t last_pid = -1; @@ -27,7 +27,7 @@ static pid_t get_pid(void) last_pid = 1; p = &task[0]; } - } while (++p < &task[MAX_TASKS]); + } while (++p < &task[max_tasks]); return last_pid; } @@ -46,7 +46,7 @@ struct task_struct *find_empty_process(void) } t = next_task_slot; while (t->state != TASK_UNUSED) { - if (++t >= &task[MAX_TASKS]) + if (++t >= &task[max_tasks]) t = &task[1]; } next_task_slot = t; diff --git a/elks/kernel/sched.c b/elks/kernel/sched.c index 49415ed87..81156b149 100644 --- a/elks/kernel/sched.c +++ b/elks/kernel/sched.c @@ -20,6 +20,7 @@ __task *task; /* dynamically allocated task array */ __ptask current; __ptask previous; +int max_tasks = MAX_TASKS; extern int intr_count; @@ -192,10 +193,10 @@ void do_timer(void) void INITPROC sched_init(void) { - register struct task_struct *t = &task[MAX_TASKS]; + struct task_struct *t = &task[max_tasks]; /* - * Mark tasks 0-(MAX_TASKS-1) as not in use. + * Mark tasks 0-(max_tasks-1) as not in use. */ do { (--t)->state = TASK_UNUSED; @@ -203,6 +204,7 @@ void INITPROC sched_init(void) current = task; next_task_slot = task; + task_slots_unused = max_tasks; /* * Now create task 0 to be ourself. */ diff --git a/elkscmd/rootfs_template/bootopts b/elkscmd/rootfs_template/bootopts index cfba76770..322925dc9 100644 --- a/elkscmd/rootfs_template/bootopts +++ b/elkscmd/rootfs_template/bootopts @@ -1,5 +1,5 @@ ## boot opts max 511 bytes -#console=ttyS0,57600 debug net=ne0 3 # sercon+multiuser+net +#console=ttyS0,57600 debug net=ne0 3 # sercon+muser+net #QEMU=1 # QEMU ftp/ftpd #TZ=MDT7 #LOCALIP=10.0.2.16 @@ -12,8 +12,9 @@ wd0=10,0x300,0xCC00,0x80 #cache=4 #xmsbuf=2975 #umb=0xC000:0x800,0xD000:0x1000 +#task=20 #sync=30 # autosync secs -#init=/bin/init 3 n # multiuser serial no rc.sys +#init=/bin/init 3 n # muser serial no rc.sys #init=/bin/sh # singleuser sh #root=hda1 ro # root hd partition 1 read-only #kstack diff --git a/elkscmd/sys_utils/meminfo.c b/elkscmd/sys_utils/meminfo.c index b14c14a97..1d8d80da4 100644 --- a/elkscmd/sys_utils/meminfo.c +++ b/elkscmd/sys_utils/meminfo.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -30,7 +31,8 @@ int allflag; /* show all memory*/ unsigned int ds; unsigned int heap_all; unsigned int taskoff; -struct task_struct task_table[MAX_TASKS]; +int maxtasks; +struct task_struct task_table; int memread(int fd, word_t off, word_t seg, void *buf, int size) { @@ -69,15 +71,23 @@ void process_name(int fd, unsigned int off, unsigned int seg) } } -int find_process(unsigned int seg) +struct task_struct *find_process(int fd, unsigned int seg) { - struct task_struct *t; - for (t = task_table; t < &task_table[MAX_TASKS]; t++) { - if ((unsigned)t->mm.seg_code == seg || (unsigned)t->mm.seg_data == seg) { - return t - task_table; + int i; + int off = taskoff; + + for (i = 0; i < maxtasks; i++) { + if (!memread(fd, off, ds, &task_table, sizeof(task_table))) { + perror("taskinfo"); + exit(1); + } + if ((unsigned)task_table.mm.seg_code == seg || + (unsigned)task_table.mm.seg_data == seg) { + return &task_table; } + off += sizeof(struct task_struct); } - return -1; + return NULL; } void dump_heap(int fd) @@ -85,7 +95,7 @@ void dump_heap(int fd) word_t total_size = 0; word_t total_free = 0; long total_segsize = 0; - static char *heaptype[] = { "free", "SEG ", "BUF ", "TTY ", "INT ", "BUFH", "PIPE" }; + static char *heaptype[] = { "free", "SEG ", "BUF ", "TTY ", "TASK", "BUFH", "PIPE" }; static char *segtype[] = { "free", "CSEG", "DSEG", "BUF ", "RDSK", "PROG" }; printf(" HEAP TYPE SIZE SEG TYPE SIZE CNT NAME\n"); @@ -99,7 +109,8 @@ void dump_heap(int fd) seg_t segbase; segext_t segsize; word_t segflags, ref_count; - int free, used, tty, buffer, t; + int free, used, tty, buffer; + struct task_struct *t; if (tag == HEAP_TAG_SEG) segflags = getword(fd, mem + offsetof(segment_s, flags), ds) & SEG_FLAG_TYPE; @@ -124,8 +135,8 @@ void dump_heap(int fd) printf(" %4x %s %7ld %4d ", segbase, segtype[segflags], (long)segsize << 4, ref_count); if (segflags == SEG_FLAG_CSEG || segflags == SEG_FLAG_DSEG) { - if ((t = find_process(mem)) >= 0) { - process_name(fd, task_table[t].t_begstack, task_table[t].t_regs.ss); + if ((t = find_process(fd, mem)) != NULL) { + process_name(fd, t->t_begstack, t->t_regs.ss); } } @@ -139,7 +150,7 @@ void dump_heap(int fd) n = getword(fd, n + offsetof(list_s, next), ds); } - printf(" Heap/free %5d/%5d Total mem %7ld\n", total_size, total_free, total_segsize); + printf(" Heap/free %5u/%5u Total mem %7ld\n", total_size, total_free, total_segsize); } void usage(void) @@ -183,7 +194,8 @@ int main(int argc, char **argv) } if (ioctl(fd, MEM_GETDS, &ds) || ioctl(fd, MEM_GETHEAP, &heap_all) || - ioctl(fd, MEM_GETTASK, &taskoff)) { + ioctl(fd, MEM_GETTASK, &taskoff) || + ioctl(fd, MEM_GETMAXTASKS, &maxtasks)) { perror("meminfo"); return 1; } diff --git a/elkscmd/sys_utils/ps.c b/elkscmd/sys_utils/ps.c index ac52c9a56..0f2f50dfc 100644 --- a/elkscmd/sys_utils/ps.c +++ b/elkscmd/sys_utils/ps.c @@ -34,6 +34,8 @@ #define LINEARADDRESS(off, seg) ((off_t) (((off_t)seg << 4) + off)) +static int maxtasks; + int memread(int fd, word_t off, word_t seg, void *buf, int size) { if (lseek(fd, LINEARADDRESS(off, seg), SEEK_SET) == -1) @@ -120,11 +122,11 @@ int main(int argc, char **argv) int c, fd; unsigned int j, ds, off; word_t cseg, dseg; - struct task_struct task_table; struct passwd * pwent; int f_listall = 0; char *progname = argv[0]; int f_uptime = !strcmp(progname, "uptime"); + struct task_struct task_table; while ((c = getopt(argc, argv, "lu")) != -1) { switch (c) { @@ -144,7 +146,8 @@ int main(int argc, char **argv) printf("ps: no /dev/kmem\n"); return 1; } - if (ioctl(fd, MEM_GETDS, &ds) < 0) { + if (ioctl(fd, MEM_GETDS, &ds) < 0 || + ioctl(fd, MEM_GETMAXTASKS, &maxtasks) < 0) { printf("ps: ioctl mem_getds\n"); return 1; } @@ -185,7 +188,7 @@ int main(int argc, char **argv) printf(" "); if (f_listall) printf("CSEG DSEG "); printf(" HEAP FREE SIZE COMMAND\n"); - for (j = 1; j < MAX_TASKS; j++) { + for (j = 1; j < maxtasks; j++) { if (!memread(fd, off + j*sizeof(struct task_struct), ds, &task_table, sizeof(task_table))) { printf("ps: memread\n"); return 1;