diff options
51 files changed, 5132 insertions, 847 deletions
@@ -5,7 +5,7 @@ UNAME := $(shell uname) -QEMU = qemu-system-i386 +QEMU = qemu-system-x86_64 QEMUOPTS = -drive file=bin/disk.img,index=0,media=disk,format=raw \ -no-reboot \ -serial mon:stdio \ @@ -44,8 +44,8 @@ bin/user.img: build cd bin && \ ./mkblob init idle prog* shell -bin/disk.img: bin/kernel.bin bin/boot.bin bin/user.img +bin/disk.img: bin/kernel.bin bin/boot.bin cd bin && \ ./BuildImage -d usb -o disk.img -b boot.bin \ - kernel.bin 0x10000 user.img 0x30000 + kernel.bin 0x10000 @@ -20,59 +20,38 @@ const c_flags = &[_][]const u8{ "-ggdb", }; -const ld_flags = &[_][]const u8{ - "-nmagic", - "-nostdlib", - "--no-warn-rwx-segments", -}; - const boot_src = &[_][]const u8{"boot/boot.S"}; const kernel_src = &[_][]const u8{ - "kernel/startup.S", // must be first - "kernel/cio.c", - "kernel/clock.c", - "kernel/isrs.S", + "kernel/entry.S", // must be first "kernel/kernel.c", - "kernel/kmem.c", - "kernel/list.c", - "kernel/procs.c", - "kernel/sio.c", - "kernel/support.c", - "kernel/syscalls.c", - "kernel/user.c", - "kernel/vm.c", - "kernel/vmtables.c", - "lib/klibc.c", }; const lib_src = &[_][]const u8{ - "lib/blkmov.c", + "lib/atox.c", "lib/bound.c", - "lib/cvtdec0.c", - "lib/cvtdec.c", - "lib/cvthex.c", - "lib/cvtoct.c", - "lib/cvtuns0.c", - "lib/cvtuns.c", - "lib/memclr.c", + "lib/btoa.c", + "lib/ctoi.c", + "lib/delay.c", + "lib/isdigit.c", + "lib/isspace.c", + "lib/itoc.c", + "lib/memcmp.c", "lib/memcpy.c", "lib/memmove.c", "lib/memset.c", - "lib/pad.c", - "lib/padstr.c", - "lib/sprint.c", - "lib/str2int.c", + "lib/printf.c", + "lib/stpcpy.c", + "lib/stpncpy.c", "lib/strcat.c", - "lib/strcmp.c", "lib/strcpy.c", "lib/strlen.c", -}; - -const ulib_src = &[_][]const u8{ - "lib/entry.S", - "lib/ulibc.c", - "lib/ulibs.S", + "lib/strncmp.c", + "lib/strncpy.c", + "lib/strtoux.c", + "lib/strtox.c", + "lib/uxtoa.c", + "lib/xtoa.c", }; const Prog = struct { @@ -98,114 +77,6 @@ const util_progs = &[_]Prog{ }, }; -const user_progs = &[_]Prog{ - // idle - Prog{ - .name = "idle", - .source = &[_][]const u8{"user/idle.c"}, - }, - // init - Prog{ - .name = "init", - .source = &[_][]const u8{"user/init.c"}, - }, - // progABC - Prog{ - .name = "progABC", - .source = &[_][]const u8{"user/progABC.c"}, - }, - // progDE - Prog{ - .name = "progDE", - .source = &[_][]const u8{"user/progDE.c"}, - }, - // progFG - Prog{ - .name = "progFG", - .source = &[_][]const u8{"user/progFG.c"}, - }, - // progH - Prog{ - .name = "progH", - .source = &[_][]const u8{"user/progH.c"}, - }, - // progI - Prog{ - .name = "progI", - .source = &[_][]const u8{"user/progI.c"}, - }, - // progJ - Prog{ - .name = "progJ", - .source = &[_][]const u8{"user/progJ.c"}, - }, - // progKL - Prog{ - .name = "progKL", - .source = &[_][]const u8{"user/progKL.c"}, - }, - // progKL - Prog{ - .name = "progKL", - .source = &[_][]const u8{"user/progKL.c"}, - }, - // progMN - Prog{ - .name = "progMN", - .source = &[_][]const u8{"user/progMN.c"}, - }, - // progP - Prog{ - .name = "progP", - .source = &[_][]const u8{"user/progP.c"}, - }, - // progQ - Prog{ - .name = "progQ", - .source = &[_][]const u8{"user/progQ.c"}, - }, - // progR - Prog{ - .name = "progR", - .source = &[_][]const u8{"user/progR.c"}, - }, - // progS - Prog{ - .name = "progS", - .source = &[_][]const u8{"user/progS.c"}, - }, - // progTUV - Prog{ - .name = "progTUV", - .source = &[_][]const u8{"user/progTUV.c"}, - }, - // progW - Prog{ - .name = "progW", - .source = &[_][]const u8{"user/progW.c"}, - }, - // progX - Prog{ - .name = "progX", - .source = &[_][]const u8{"user/progX.c"}, - }, - // progY - Prog{ - .name = "progY", - .source = &[_][]const u8{"user/progY.c"}, - }, - // progZ - Prog{ - .name = "progZ", - .source = &[_][]const u8{"user/progZ.c"}, - }, - // shell - Prog{ - .name = "shell", - .source = &[_][]const u8{"user/shell.c"}, - }, -}; - const AddSourcesOpts = struct { exe: *std.Build.Step.Compile, sources: []const []const []const u8, c_flags: []const []const u8 }; fn add_sources(b: *std.Build, opts: AddSourcesOpts) void { @@ -231,6 +102,7 @@ const BuildKernBinaryOpts = struct { linker: ?[]const u8 = null, entry: []const u8 = "_start", strip: bool = false, + include: ?[]const u8 = null, }; fn build_kern_binary(b: *std.Build, opts: BuildKernBinaryOpts) void { @@ -242,8 +114,13 @@ fn build_kern_binary(b: *std.Build, opts: BuildKernBinaryOpts) void { .strip = opts.strip, }); - // add include path + // add include paths exe.addIncludePath(b.path("include/")); + if (opts.include != null) { + exe.addIncludePath(b.path(opts.include.?)); + } + + // set entry exe.entry = .{ .symbol_name = opts.entry }; // add asm and c source files @@ -297,56 +174,46 @@ fn build_native_binary(b: *std.Build, opts: BuildNativeBinaryOpts) void { pub fn build(b: *std.Build) !void { // context - const target = b.standardTargetOptions(.{ - .default_target = .{ - .cpu_arch = std.Target.Cpu.Arch.x86, - .os_tag = std.Target.Os.Tag.freestanding, - .abi = std.Target.Abi.gnu, - .ofmt = std.Target.ObjectFormat.elf, - }, + const target32 = std.Build.resolveTargetQuery(b, .{ + .cpu_arch = std.Target.Cpu.Arch.x86, + .os_tag = std.Target.Os.Tag.freestanding, + .abi = std.Target.Abi.gnu, + .ofmt = std.Target.ObjectFormat.elf, + }); + const target64 = std.Build.resolveTargetQuery(b, .{ + .cpu_arch = std.Target.Cpu.Arch.x86_64, + .os_tag = std.Target.Os.Tag.freestanding, + .abi = std.Target.Abi.gnu, + .ofmt = std.Target.ObjectFormat.elf, }); const optimize = std.builtin.OptimizeMode.ReleaseFast; // boot build_kern_binary(b, .{ .name = "boot", - .target = target, + .target = target32, .optimize = optimize, .sources = &.{ boot_src, }, .linker = "boot/boot.ld", .entry = "bootentry", + .include = "boot/include", }); // kernel build_kern_binary(b, .{ .name = "kernel", - .target = target, + .target = target64, .optimize = optimize, .sources = &.{ kernel_src, lib_src, }, .linker = "kernel/kernel.ld", + .include = "kernel/include", }); - // user_progs - for (user_progs) |prog| { - build_kern_binary(b, .{ - .name = prog.name, - .target = target, - .optimize = optimize, - .sources = &.{ - prog.source, - lib_src, - ulib_src, - }, - .linker = "user/user.ld", - .strip = true, - }); - } - // util_progs for (util_progs) |prog| { build_native_binary(b, .{ diff --git a/compile_flags.txt b/compile_flags.txt index 24e70cc..924a806 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -1,6 +1,7 @@ -c -std=c99 -Iinclude +-Ikernel/include -ffreestanding -fno-builtin -Wall diff --git a/kernel/entry.S b/kernel/entry.S new file mode 100644 index 0000000..5d763ed --- /dev/null +++ b/kernel/entry.S @@ -0,0 +1,158 @@ + .globl _start + .globl kernel_pml4 + .globl kernel_pdpt_0 + .globl kernel_pd_0 + .globl kernel_pt_0 + .globl paging_pt + .globl bootstrap_pt + .extern main + .extern GDT + + .section .bss + + # kernel page tables + .align 4096 +kernel_pml4: # reserve memory for initial 512 pml4 entires + .skip 4096 +kernel_pdpt_0: # reserve memory for initial 512 pdpt entires + .skip 4096 +kernel_pd_0: # reserve memory for initial 512 pd entries + .skip 4096 +kernel_pt_0: # reserve memory for initial 512 pt entries + .skip 4096 +paging_pt: # reserve pages for pager mappings + .skip 4096 +bootstrap_pt: # reserve pages to bootstrap pager + .skip 4096 + + # kernel stack + .align 16 +kern_stack_start: + .skip 8192 +kern_stack_end: + + .section .rodata + .align 16 + + # access bits + .set PRESENT, 1 << 7 + .set NOT_SYS, 1 << 4 + .set EXEC, 1 << 3 + .set DC, 1 << 2 + .set RW, 1 << 1 + .set ACCESSED, 1 << 0 + + # flag bits + .set GRAN_4K, 1 << 7 + .set SZ_32, 1 << 6 + .set LONG_MODE, 1 << 5 + + # kernel gdt (long mode) +GDT: + GDT.Null: + .quad 0 + + GDT.Code: + .byte 0 + .byte PRESENT | NOT_SYS | EXEC | RW + .byte GRAN_4K | LONG_MODE | 0xF + .byte 0 + + GDT.Data: + .long 0xFFFF + .byte 0 + .byte PRESENT | NOT_SYS | RW + .byte GRAN_4K | SZ_32 | 0xF + .byte 0 + + GDT.TSS: + .long 0x00000068 + .long 0x00CF8900 + + GDT.Pointer: + .short . - GDT - 1 + .quad GDT - . + + .section .text + .code32 + +_start: + # enable interrupts + cli + + # setup stack + movl $kern_stack_end, %esp + movl $kern_stack_end, %ebp + + # save multiboot (if using multiboot) + pushl $0 + push %ebx + pushl $0 + push %eax + + # zero out kernel page table + movl $0x1000, %edi # kernel is loaded at 0x1000 + movl %edi, %cr3 + xorl %eax, %eax + movl $4096, %ecx # zero 4096 pages + rep stosl + movl %cr3, %edi + + # identity map kernel + movl $kernel_pdpt_0 + 3, (%edi) # Set the uint32_t at the desination index to 0x2003. + movl $kernel_pdpt_0, %edi # Add 0x1000 to the desination index. + movl $kernel_pd_0 + 3, (%edi) # Set the uint32_t at the desination index to 0x3003. + movl $kernel_pd_0, %edi # Add 0x1000 to the desination index. + movl $kernel_pt_0 + 3, (%edi) # Set the uint32_t at the desination index to 0x4003. + movl $kernel_pt_0, %edi # Add 0x1000 to the desination index. + + movl $0x00000003, %ebx # Entry value to set + movl $512, %ecx # Loop count + +set_entry: + # set entires in mapping + movl %ebx, (%edi) # Set the uint32_t at the desination index to the B-register + addl $0x1000, %ebx # Add 0x1000 to the B-register + addl $8, %edi # Add eight to the desination index + loop set_entry + + # enable page address extension + movl %cr4, %eax + orl $(1 << 5), %eax + movl %eax, %cr4 + + # enable long mode + movl $0xC0000080, %eax + rdmsr + orl $(1 << 8), %eax + wrmsr + + # enable paging + movl %cr0, %eax + orl $(1 << 31), %eax + movl %eax, %cr0 + + # load gdt + lgdt GDT.Pointer + ljmp $16, $code64 + + .code64 +code64: + + movw $16, %dx # set segment registers + movw %dx, %ds + movw %dx, %ss + + xorq %rbp, %rbp # set ebp to 0 so we know where to end stack traces + + pop %rdi # pop possible multiboot header + pop %rsi + + sti + call main + cli + + halt: + hlt + jmp halt + diff --git a/kernel/include/comus/memory.h b/kernel/include/comus/memory.h new file mode 100644 index 0000000..938bc6b --- /dev/null +++ b/kernel/include/comus/memory.h @@ -0,0 +1 @@ +#include <memory/mapping.h> diff --git a/kernel/include/comus/memory/mapping.h b/kernel/include/comus/memory/mapping.h new file mode 100644 index 0000000..e1b7102 --- /dev/null +++ b/kernel/include/comus/memory/mapping.h @@ -0,0 +1,20 @@ +/** + * @file memory.h + * + * @author Freya Murphy + * + * Kernel memory declarations + */ + +#ifndef _MEMORY_MAPPING_H +#define _MEMORY_MAPPING_H + +// paging +#define PAGE_SIZE 4096 +#define PAGE_PRESENT 0x1 +#define PAGE_WRITE 0x2 +#define PAGE_USER 0x4 +#define PAGE_HUGE 0x80 +#define PAGE_GLOBAL 0x100 + +#endif diff --git a/kernel/kernel.c b/kernel/kernel.c index ce2e9dd..075c878 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -1,400 +1,5 @@ -/** -** @file kernel.c -** -** @author CSCI-452 class of 20245 -** -** @brief Kernel support routines -*/ -#define KERNEL_SRC -#include <common.h> -#include <cio.h> -#include <clock.h> -#include <kmem.h> -#include <procs.h> -#include <sio.h> -#include <syscalls.h> -#include <user.h> -#include <userids.h> -#include <vm.h> - -/* -** PRIVATE DEFINITIONS -*/ - -/* -** PRIVATE DATA TYPES -*/ - -/* -** PRIVATE GLOBAL VARIABLES -*/ - -/* -** PUBLIC GLOBAL VARIABLES -*/ - -// character buffers, usable throughout the OS -// nto guaranteed to retain their contents across an exception return -char b256[256]; // primarily used for message creation -char b512[512]; // used by PANIC macro - -/* -** PRIVATE FUNCTIONS -*/ - -/* -** PRIVATE FUNCTIONS -*/ - -/** -** report - report the system configuration -** -** Prints configuration information about the OS on the console monitor. -** -** @param dtrace Decode the TRACE options -*/ -static void kreport(bool_t dtrace) -{ - cio_puts("\n-------------------------------\n"); - cio_printf("Config: N_PROCS = %d", N_PROCS); - cio_printf(" N_PRIOS = %d", N_PRIOS); - cio_printf(" N_STATES = %d", N_STATES); - cio_printf(" CLOCK = %dHz\n", CLOCK_FREQ); - - // This code is ugly, but it's the simplest way to - // print out the values of compile-time options - // without spending a lot of execution time at it. - - cio_puts("Options: " -#ifdef RPT_INT_UNEXP - " R-uint" -#endif -#ifdef RPT_INT_MYSTERY - " R-mint" -#endif -#ifdef TRACE_CX - " CX" -#endif -#ifdef CONSOLE_STATS - " Cstats" -#endif - ); // end of cio_puts() call - -#ifdef SANITY - cio_printf(" SANITY = %d", SANITY); -#endif -#ifdef STATUS - cio_printf(" STATUS = %d", STATUS); -#endif - -#if TRACE > 0 - cio_printf(" TRACE = 0x%04x\n", TRACE); - - // decode the trace settings if that was requested - if (TRACING_SOMETHING && dtrace) { - // this one is simpler - we rely on string literal - // concatenation in the C compiler to create one - // long string to print out - - cio_puts("Tracing:" -#if TRACING_PCB - " PCB" -#endif -#if TRACING_VM - " VM" -#endif -#if TRACING_QUEUE - " QUE" -#endif -#if TRACING_SCHED - " SCHED" -#endif -#if TRACING_DISPATCH - " DISPATCH" -#endif -#if TRACING_SYSCALLS - " SCALL" -#endif -#if TRACING_SYSRETS - " SRET" -#endif -#if TRACING_EXIT - " EXIT" -#endif -#if TRACING_INIT - " INIT" -#endif -#if TRACING_KMEM - " KM" -#endif -#if TRACING_KMEM_FREELIST - " KMFL" -#endif -#if TRACING_KMEM_INIT - " KMIN" -#endif -#if TRACING_FORK - " FORK" -#endif -#if TRACING_EXEC - " EXEC" -#endif -#if TRACING_SIO_STAT - " S_STAT" -#endif -#if TRACING_SIO_ISR - " S_ISR" -#endif -#if TRACING_SIO_RD - " S_RD" -#endif -#if TRACING_SIO_WR - " S_WR" -#endif -#if TRACING_USER - " USER" -#endif -#if TRACING_ELF - " ELF" -#endif - ); // end of cio_puts() call - } -#endif /* TRACE > 0 */ - - cio_putchar('\n'); -} - -#if defined(CONSOLE_STATS) -/** -** stats - callback routine for console statistics -** -** Called by the CIO module when a key is pressed on the -** console keyboard. Depending on the key, it will print -** statistics on the console display, or will cause the -** user shell process to be dispatched. -** -** This code runs as part of the CIO ISR. -*/ -static void stats(int code) -{ - switch (code) { - case 'a': // dump the active table - ptable_dump("\nActive processes", false); - break; - - case 'c': // dump context info for all active PCBs - ctx_dump_all("\nContext dump"); - break; - - case 'p': // dump the active table and all PCBs - ptable_dump("\nActive processes", true); - break; - - case 'q': // dump the queues - // code to dump out any/all queues - pcb_queue_dump("R", ready, true); - pcb_queue_dump("W", waiting, true); - pcb_queue_dump("S", sleeping, true); - pcb_queue_dump("Z", zombie, true); - pcb_queue_dump("I", sioread, true); - break; - - case 'r': // print system configuration information - report(true); - break; - - // ignore CR and LF - case '\r': // FALL THROUGH - case '\n': - break; - - default: - cio_printf("console: unknown request '0x%02x'\n", code); - // FALL THROUGH - - case 'h': // help message - cio_puts("\nCommands:\n" - " a -- dump the active table\n" - " c -- dump contexts for active processes\n" - " h -- this message\n" - " p -- dump the active table and all PCBs\n" - " q -- dump the queues\n" - " r -- print system configuration\n"); - break; - } -} -#endif - -/* -** PUBLIC FUNCTIONS -*/ - -/** -** main - system initialization routine -** -** Called by the startup code immediately before returning into the -** first user process. -** -** Making this type 'int' keeps the compiler happy. -*/ -int main(void) -{ - /* - ** BOILERPLATE CODE - taken from basic framework - ** - ** Initialize interrupt stuff. - */ - - init_interrupts(); // IDT and PIC initialization - - /* - ** Console I/O system. - ** - ** Does not depend on the other kernel modules, so we can - ** initialize it before we initialize the kernel memory - ** and queue modules. - */ - -#if defined(CONSOLE_STATS) - cio_init(stats); -#else - cio_init(NULL); // no console callback routine -#endif - - cio_clearscreen(); // wipe out whatever is there - - /* - ** TERM-SPECIFIC CODE STARTS HERE - */ - - /* - ** Initialize various OS modules - ** - ** Other modules (clock, SIO, syscall, etc.) are expected to - ** install their own ISRs in their initialization routines. - */ - - cio_puts("System initialization starting.\n"); - cio_puts("-------------------------------\n"); - - cio_puts("Modules:"); - - // call the module initialization functions, being - // careful to follow any module precedence requirements - - km_init(); // MUST BE FIRST -#if TRACING_KMEM || TRACING_KMEM_FREE - delay(DELAY_2_SEC); // approximately -#endif - - // other module initialization calls here - clk_init(); // clock - pcb_init(); // process (PCBs, queues, scheduler) -#if TRACING_PCB - delay(DELAY_2_SEC); -#endif - sio_init(); // serial i/o - sys_init(); // system call -#if TRACING_SYSCALLS || TRACING_SYSRETS - delay(DELAY_2_SEC); -#endif - vm_init(); // virtual memory - user_init(); // user code handling - - cio_puts("\nModule initialization complete.\n"); - - // report our configuration options - kreport(true); - cio_puts("-------------------------------\n"); - - delay(DELAY_2_SEC); - - /* - ** Other tasks typically performed here: - ** - ** Enabling any I/O devices (e.g., SIO xmit/rcv) - */ - - /* - ** Create the initial user process - ** - ** This code is largely stolen from the fork() and exec() - ** implementations in syscalls.c; if those change, this must - ** also change. - */ - - // if we can't get a PCB, there's no use continuing! - assert(pcb_alloc(&init_pcb) == SUCCESS); - - // fill in the necessary details - init_pcb->pid = PID_INIT; - init_pcb->state = STATE_NEW; - init_pcb->priority = PRIO_HIGH; - - // find the 'init' program - prog_t *prog = user_locate(Init); - assert(prog != NULL); - - // command-line arguments for 'init' - const char *args[2] = { "init", NULL }; - - // load it - assert(user_load(prog, init_pcb, args, true) == SUCCESS); - - // send it on its merry way - schedule(init_pcb); - dispatch(); - -#ifdef TRACE_CX - // if we're using a scrolling region, wait a bit more and then set it up - delay(DELAY_7_SEC); - - // define a scrolling region in the top 7 lines of the screen - cio_setscroll(0, 7, 99, 99); - - // clear it - cio_clearscroll(); - - // clear the top line - cio_puts_at( - 0, 0, - "* "); - // separator - cio_puts_at( - 0, 6, - "================================================================================"); -#endif - - /* - ** END OF TERM-SPECIFIC CODE - ** - ** Finally, report that we're all done. - */ - - cio_puts("System initialization complete.\n"); - cio_puts("-------------------------------\n"); - - sio_enable(SIO_RX); - -#if 0 - // produce a "system state" report - cio_puts( "System status: Queues " ); - pcb_queue_dump( "R", ready, true ); - pcb_queue_dump( "W", waiting, true ); - pcb_queue_dump( "S", sleeping, true ); - pcb_queue_dump( "Z", zombie, true ); - pcb_queue_dump( "I", sioread, true ); - ptable_dump_counts(); - pcb_dump( "Current: ", current, true ); - - delay( DELAY_3_SEC ); - - vm_print( current->pdir, true, TwoLevel ); - - delay( DELAY_3_SEC ); -#endif - - return 0; +void main(void) { + while (1) ; } diff --git a/kernel/kernel.ld b/kernel/kernel.ld index 83f211c..eed5e20 100644 --- a/kernel/kernel.ld +++ b/kernel/kernel.ld @@ -1,71 +1,30 @@ -/* -** Simple linker script for the 20245 kernel. -*/ - -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) ENTRY(_start) SECTIONS { - /* Link the kernel at this address. */ - /* Must match what is defined in vm.h! */ - . = 0x80010000; + . = 1M; - .text : AT(0x10000) { + .text : { *(.text .stub .text.* .gnu.linkonce.t.*) } - /* standard symbols */ - PROVIDE(etext = .); - PROVIDE(_etext = .); - - /* put read-only data next */ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - /* Could put STABs here */ - /* - .stab : { - PROVIDE(__STAB_BEGIN__ = .); - *(.stab); - PROVIDE(__STAB_END__ = .); - } - .stabstr : { - PROVIDE(__STABSTR_BEGIN__ = .); - *(.stabstr); - PROVIDE(__STABSTR_END__ = .); - } - */ - - /* Align the data segment at the next page boundary */ . = ALIGN(0x1000); - PROVIDE(data = .); - PROVIDE(_data = .); - - /* The data segment */ .data : { *(.data .data.*) } - PROVIDE(edata = .); - PROVIDE(_edata = .); - - /* page-align the BSS */ . = ALIGN(0x1000); - PROVIDE(__bss_start = .); - .bss : { - *(.bss .bss.*) *(COMMON) + *(.bss .bss.*) } - PROVIDE(end = .); - PROVIDE(_end = .); - /DISCARD/ : { *(.stab .stab_info .stabstr) *(.eh_frame .eh_frame_hdr) diff --git a/kernel/cio.c b/kernel/old/cio.c index deb6b76..deb6b76 100644 --- a/kernel/cio.c +++ b/kernel/old/cio.c diff --git a/kernel/clock.c b/kernel/old/drivers/clock.c index 7af47b7..9f3d4be 100644 --- a/kernel/clock.c +++ b/kernel/old/drivers/clock.c @@ -1,11 +1,3 @@ -/** -** @file clock.c -** -** @author CSCI-452 class of 20245 -** -** @brief Clock module implementation -*/ - #define KERNEL_SRC #include <common.h> diff --git a/kernel/sio.c b/kernel/old/drivers/serial.c index 8bcc8a1..d6572e5 100644 --- a/kernel/sio.c +++ b/kernel/old/drivers/serial.c @@ -1,64 +1,3 @@ -/** -** @file sio.c -** -** @author Warren R. Carithers -** -** @brief SIO module -** -** For maximum compatibility from semester to semester, this code uses -** several "stand-in" type names and macros which should be defined -** in the accompanying "compat.h" header file if they're not part of -** the baseline system: -** -** standard-sized integer types: intN_t, uintN_t -** other types: PCBTYPE, QTYPE -** scheduler functions: SCHED, DISPATCH -** queue functions: QCREATE, QLENGTH, QDEQUE -** other functions: SLENGTH -** sio read queue: QNAME -** -** Our SIO scheme is very simple: -** -** Input: We maintain a buffer of incoming characters that haven't -** yet been read by processes. When a character comes in, if -** there is no process waiting for it, it goes in the buffer; -** otherwise, the first waiting process is awakeneda and it -** gets the character. -** -** When a process invokes readch(), if there is a character in -** the input buffer, the process gets it; otherwise, it is -** blocked until input appears -** -** Communication with system calls is via two routines. -** sio_readc() returns the first available character (if -** there is one), resetting the input variables if this was -** the last character in the buffer. If there are no -** characters in the buffer, sio_read() returns a -1 -** (presumably so the requesting process can be blocked). -** -** sio_read() copies the contents of the input buffer into -** a user-supplied buffer. It returns the number of characters -** copied. If there are no characters available, return a -1. -** -** Output: We maintain a buffer of outgoing characters that haven't -** yet been sent to the device, and an indication of whether -** or not we are in the middle of a transmit sequence. When -** an interrupt comes in, if there is another character to -** send we copy it to the transmitter buffer; otherwise, we -** end the transmit sequence. -** -** Communication with user processes is via three functions. -** sio_writec() writes a single character; sio_write() -** writes a sized buffer full of characters; sio_puts() -** prints a NUL-terminated string. If we are in the middle -** of a transmit sequence, all characters will be added -** to the output buffer (from where they will be sent -** automatically); otherwise, we send the first character -** directly, add the rest of the characters (if there are -** any) to the output buffer, and set the "sending" flag -** to indicate that we're expecting a transmitter interrupt. -*/ - #define KERNEL_SRC // this should do all includes required for this OS diff --git a/kernel/old/include/bindings.h b/kernel/old/include/bindings.h new file mode 100644 index 0000000..365abc9 --- /dev/null +++ b/kernel/old/include/bindings.h @@ -0,0 +1,73 @@ +/** + * @file bindings.h + * @author Freya Murphy <freya@freyacat.org> + * + * C-style function definitions binded to their named assembly instruction. + */ + +#ifndef _BINDINGS_H +#define _BINDINGS_H +#include <types.h> + +static inline uint8_t inb(uint16_t port) +{ + uint8_t ret; + __asm__ volatile("inb %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} + +static inline void outb(uint16_t port, uint8_t val) +{ + __asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port)); +} + +static inline uint16_t inw(uint16_t port) +{ + uint16_t ret; + __asm__ volatile("inw %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} + +static inline void outw(uint16_t port, uint16_t val) +{ + __asm__ volatile("outw %0, %1" : : "a"(val), "Nd"(port)); +} + +static inline uint32_t inl(uint16_t port) +{ + uint32_t ret; + __asm__ volatile("inl %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} + +static inline void outl(uint16_t port, uint32_t val) +{ + __asm__ volatile("outl %0, %1" : : "a"(val), "Nd"(port)); +} + +static inline void io_wait(void) +{ + outb(0x80, 0); +} + +static inline void sti(void) +{ + __asm__ volatile("sti"); +} + +static inline void cli(void) +{ + __asm__ volatile("cli"); +} + +static inline void int_wait(void) +{ + __asm__ volatile("sti; hlt"); +} + +static inline void halt(void) +{ + __asm__ volatile("cli; hlt"); +} + +#endif /* bindings.h */ diff --git a/kernel/old/include/bootstrap.h b/kernel/old/include/bootstrap.h new file mode 100644 index 0000000..6c6dfcc --- /dev/null +++ b/kernel/old/include/bootstrap.h @@ -0,0 +1,119 @@ +/* +** SCCS ID: @(#)bootstrap.h 2.4 1/22/25 +** +** @file bootstrap.h +** +** @author K. Reek +** @author Warren R. Carithers, Garrett C. Smith +** +** Addresses where various stuff goes in memory. +*/ + +#ifndef BOOTSTRAP_H_ +#define BOOTSTRAP_H_ + +/* +** The boot device +*/ +#define BDEV_FLOPPY 0x00 +#define BDEV_USB 0x80 /* hard drive */ + +#define BDEV BDEV_USB /* default */ + +/* +** Bootstrap definitions +*/ +#define BOOT_SEG 0x07c0 /* 07c0:0000 */ +#define BOOT_DISP 0x0000 +#define BOOT_ADDR ((BOOT_SEG << 4) + BOOT_DISP) + +#define PART2_DISP 0x0200 /* 07c0:0200 */ +#define PART2_ADDR ((BOOT_SEG << 4) + PART2_DISP) + +#define SECTOR_SIZE 0x200 /* 512 bytes */ + +/* Note: this assumes the bootstrap is two sectors long! */ +#define BOOT_SIZE (SECTOR_SIZE + SECTOR_SIZE) + +#define OFFSET_LIMIT (0x10000 - SECTOR_SIZE) + +#define BOOT_SP_DISP 0x4000 /* stack pointer 07c0:4000, or 0xbc00 */ +#define BOOT_SP_ADDR ((BOOT_SEG << 4) + BOOT_SP_DISP) + +#define SECTOR1_END (BOOT_ADDR + SECTOR_SIZE) +#define SECTOR2_END (BOOT_ADDR + BOOT_SIZE) + +// location of the user blob data +// (three halfwords of data) +#define USER_BLOB_DATA (SECTOR2_END - 12) + +/* +** The target program itself +*/ +#define TARGET_SEG 0x00001000 /* 1000:0000 */ +#define TARGET_ADDR 0x00010000 /* and upward */ +#define TARGET_STACK 0x00010000 /* and downward */ + +/* +** The Global Descriptor Table (0000:0500 - 0000:2500) +*/ +#define GDT_SEG 0x00000050 +#define GDT_ADDR 0x00000500 + +/* segment register values */ +#define GDT_LINEAR 0x0008 /* All of memory, R/W */ +#define GDT_CODE 0x0010 /* All of memory, R/E */ +#define GDT_DATA 0x0018 /* All of memory, R/W */ +#define GDT_STACK 0x0020 /* All of memory, R/W */ + +/* +** The Interrupt Descriptor Table (0000:2500 - 0000:2D00) +*/ +#define IDT_SEG 0x00000250 +#define IDT_ADDR 0x00002500 + +/* +** Additional I/O ports used by the bootstrap code +*/ + +// keyboard controller +#define KBD_DATA 0x60 +#define KBD_CMD 0x64 +#define KBD_STAT 0x64 + +// status register bits +#define KBD_OBSTAT 0x01 +#define KBD_IBSTAT 0x02 +#define KBD_SYSFLAG 0x04 +#define KBD_CMDDAT 0x08 + +// commands +#define KBD_P1_DISABLE 0xad +#define KBD_P1_ENABLE 0xae +#define KBD_RD_OPORT 0xd0 +#define KBD_WT_OPORT 0xd1 + +#ifdef ASM_SRC + +// segment descriptor macros for use in assembly source files +// layout: +// .word lower 16 bits of limit +// .word lower 16 bits of base +// .byte middle 8 bits of base +// .byte type byte +// .byte granularity byte +// .byte upper 8 bits of base +// we use 4K units, so we ignore the lower 12 bits of the limit +#define SEGNULL .word 0, 0, 0, 0 + +#define SEGMENT(base, limit, dpl, type) \ + .word(((limit) >> 12) & 0xffff); \ + .word((base) & 0xffff); \ + .byte(((base) >> 16) & 0xff); \ + .byte(SEG_PRESENT | (dpl) | SEG_NON_SYSTEM | (type)); \ + .byte(SEG_GRAN_4KBYTE | SEG_DB_32BIT | (((limit) >> 28) & 0xf)); \ + .byte(((base) >> 24) & 0xff) + +#endif /* ASM_SRC */ + +#endif diff --git a/kernel/old/include/cio.h b/kernel/old/include/cio.h new file mode 100644 index 0000000..63bf827 --- /dev/null +++ b/kernel/old/include/cio.h @@ -0,0 +1,287 @@ +/** +** SCCS ID: @(#)cio.h 2.7 1/22/25 +** +** @file cio.h +** +** @author Warren R. Carithers +** @authors K. Reek, Jon Coles +** +** Based on: c_io.c 1.13 (Ken Reek, Jon Coles, Warren R. Carithers) +** +** Declarations and descriptions of console I/O routines +** +** These routines provide a rudimentary capability for printing to +** the screen and reading from the keyboard. +** +** Screen output: +** There are two families of functions. The first provides a window +** that behaves in the usual manner: writes extending beyond the right +** edge of the window wrap around to the next line, the top line +** scrolls off the window to make room for new lines at the bottom. +** However, you may choose what part of the screen contains this +** scrolling window. This allows you to print some text at fixed +** locations on the screen while the rest of the screen scrolls. +** +** The second family allows for printing at fixed locations on the +** screen. No scrolling or line wrapping are done for these functions. +** It is not intended that these functions be used to write in the +** scrolling area of the screen. +** +** In both sets of functions, the (x,y) coordinates are interpreted +** as (column,row), with the upper left corner of the screen being +** (0,0) and the lower right corner being (79,24). +** +** The printf provided in both sets of functions has the same +** conversion capabilities. Format codes are of the form: +** +** %-0WC +** +** where "-", "0", and "W" are all optional: +** "-" is the left-adjust flag (default is right-adjust) +** "0" is the zero-fill flag (default is space-fill) +** "W" is a number specifying the minimum field width (default: 1 ) +** and "C" is the conversion type, which must be one of these: +** "c" print a single character +** "s" print a null-terminated string +** "d" print an integer as a decimal value +** "x" print an integer as a hexadecimal value +** "o" print an integer as a octal value +** +** Keyboard input: +** Two functions are provided: getting a single character and getting +** a newline-terminated line. A third function returns a count of +** the number of characters available for immediate reading. +** No conversions are provided (yet). +*/ + +#ifndef CIO_H_ +#define CIO_H_ + +#ifndef ASM_SRC + +// EOT indicator (control-D) +#define EOT '\04' + +/***************************************************************************** +** +** INITIALIZATION ROUTINES +** +** Initializes the I/O system. +*/ + +/** +** cio_init +** +** Initializes the I/O routines. Must be called before +** any CIO functions can be used. +** +** @param notify pointer to an input notification function, or NULL +*/ +void cio_init(void (*notify)(int)); + +/***************************************************************************** +** +** SCROLLING OUTPUT ROUTINES +** +** Each operation begins at the current cursor position and advances +** it. If a newline is output, the reminder of that line is cleared. +** Output extending past the end of the line is wrapped. If the +** cursor is moved below the scrolling region's bottom edge, scrolling +** is delayed until the next output is produced. +*/ + +/** +** cio_setscroll +** +** This sets the scrolling region to be the area defined by the arguments. +** The remainder of the screen does not scroll and may be used to display +** data you do not want to move. By default, the scrolling region is the +** entire screen. X and Y coordinates begin at 0 in the upper left corner +** of the screen. +** +** @param min_x,min_y upper-left corner of the region +** @param max_x,max_y lower-right corner of the region +*/ +void cio_setscroll(unsigned int min_x, unsigned int min_y, unsigned int max_x, + unsigned int max_y); + +/** +** cio_moveto +** +** Moves the cursor to the specified position. (0,0) indicates +** the upper left corner of the scrolling region. Subsequent +** output will begin at the cursor position. +** +** @param x,y desired coordinate position +*/ +void cio_moveto(unsigned int x, unsigned int y); + +/** +** cio_putchar +** +** Prints a single character. +** +** @param c the character to be printed +*/ +void cio_putchar(unsigned int c); + +/** +** cio_puts +** +** Prints the characters in the string up to but not including +** the terminating null byte. +** +** @param str pointer to a NUL-terminated string to be printed +*/ +void cio_puts(const char *str); + +/** +** cio_write +** +** Prints "length" characters from the buffer. +** +** @param buf the buffer of characters +** @param length the number of characters to print +*/ +void cio_write(const char *buf, int length); + +/** +** cio_printf +** +** Limited form of printf (see the beginning of this file for +** a list of what is implemented). +** +** @param fmt a printf-style format control string +** @param ... optional additional values to be printed +*/ +void cio_printf(char *fmt, ...); + +/** +** cio_scroll +** +** Scroll the scrolling region up by the given number of lines. +** The output routines scroll automatically so normally you +** do not need to call this routine yourself. +** +** @param lines the number of lines to scroll +*/ +void cio_scroll(unsigned int lines); + +/** +** cio_clearscroll +** +** Clears the entire scrolling region to blank spaces, and +** moves the cursor to (0,0). +*/ +void cio_clearscroll(void); + +/***************************************************************************** +** +** NON-SCROLLING OUTPUT ROUTINES +** +** Coordinates are relative to the entire screen: (0,0) is the upper +** left corner. There is no line wrap or scrolling. +*/ + +/** +** cio_putchar_at +** +** Prints the given character. If a newline is printed, +** the rest of the line is cleared. If this happens to the +** left of the scrolling region, the clearing stops when the +** region is reached. If this happens inside the scrolling +** region, the clearing stops when the edge of the region +** is reached. +** +** @param x,y desired coordinate position +** @param c the character to be printed +*/ +void cio_putchar_at(unsigned int x, unsigned int y, unsigned int c); + +/** +** cio_puts_at +** +** Prints the given string. cio_putchar_at is used to print +** the individual characters; see that description for details. +** +** @param x,y desired coordinate position +** @param str pointer to a NUL-terminated string to be printed +*/ +void cio_puts_at(unsigned int x, unsigned int y, const char *str); + +/** +** cio_printf_at +** +** Limited form of printf (see the beginning of this file for +** a list of what is implemented). +** +** @param x,y desired coordinate position +** @param fmt a printf-style format control string +** @param ... optional additional values to be printed +*/ +void cio_printf_at(unsigned int x, unsigned int y, char *fmt, ...); + +/** +** cio_clearscreen +** +** This function clears the entire screen, including the scrolling region. +*/ +void cio_clearscreen(void); + +/***************************************************************************** +** +** INPUT ROUTINES +** +** When interrupts are enabled, a keyboard ISR collects keystrokes +** and saves them until the program calls for them. If the input +** queue fills, additional characters are silently discarded. +** When interrupts are not enabled, keystrokes made when no input +** routines have been ** called are lost. This can cause errors in +** the input translation because the states of the Shift and Ctrl keys +** may not be tracked accurately. If interrupts are disabled, the user +** is advised to refrain from typing anything except when the program is +** waiting for input. +*/ + +/** +** cio_getchar +** +** If the character is not immediately available, the function +** waits until the character arrives. +** +** @return the next character from the keyboard input buffer +*/ +int cio_getchar(void); + +/** +** cio_gets +** +** This function reads a newline-terminated line from the +** keyboard. cio_getchar is used to obtain the characters; +** see that description for more details. The function +** returns when: +** a newline is entered (this is stored in the buffer) +** ctrl-D is entered (not stored in the buffer) +** the buffer becomes full. +** The buffer is null-terminated in all cases. +** +** @param buffer destination buffer for the input character sequence +** @param size the buffer length +** +** @return count of the number of characters read into the buffer +*/ +int cio_gets(char *buffer, unsigned int size); + +/** +** cio_input_queue +** +** This function lets the program determine whether there is input +** available. This indicates whether or not a call to cio_getchar() +** would block. +** +** @return number of characters in the input queue +*/ +int cio_input_queue(void); +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/clock.h b/kernel/old/include/clock.h new file mode 100644 index 0000000..674d799 --- /dev/null +++ b/kernel/old/include/clock.h @@ -0,0 +1,55 @@ +/** +** @file clock.h +** +** @author CSCI-452 class of 20245 +** +** @brief Clock module declarations +*/ + +#ifndef CLOCK_H_ +#define CLOCK_H_ + +#include <common.h> + +/* +** General (C and/or assembly) definitions +*/ + +// conversion functions for seconds, ms, and ticks +// (SEC_TO_MS is defined in defs.h) +#define MS_TO_TICKS(n) ((n)) +#define SEC_TO_TICKS(n) (MS_TO_TICKS(SEC_TO_MS(n))) +#define TICKS_TO_SEC(n) ((n) / CLOCK_FREQ) +#define TICKS_TO_SEC_ROUNDED(n) (((n) + (CLOCK_FREQ - 1)) / CLOCK_FREQ) + +#ifndef ASM_SRC + +/* +** Start of C-only definitions +*/ + +/* +** Types +*/ + +/* +** Globals +*/ + +// current system time +extern uint32_t system_time; + +/* +** Prototypes +*/ + +/** +** Name: clk_init +** +** Clock module initialization +*/ +void clk_init(void); + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/compat.h b/kernel/old/include/compat.h new file mode 100644 index 0000000..f0c8c97 --- /dev/null +++ b/kernel/old/include/compat.h @@ -0,0 +1,132 @@ +/** +** @file compat.h +** +** @author Warren R. Carithers +** +** @brief Compatibility definitions for standard modules. +** +** These definitions are here to simplify the integration +** of some pre-written modules into the 452 baseline system. +** This is used primarily for the 'kmem' and 'sio' modules. +** +** We use CPP symbols and not actual data types for things here, +** as this means we don't need to include any other header files +** into this file. This helps get around "include loops" (e.g., +** a.h includes b.h, which includes c.h, which includes a.h) when +** there are many interdependencies between source files. +*/ + +#ifndef COMPAT_H_ +#define COMPAT_H_ + +#include <common.h> +#include <procs.h> + +/* +** Section 1: sized integer types +** +** Internally, we use standard names for "sized" integer types for +** simplicity. If those disagree with the names used in the rest of +** the system, we take the opportunity to define our names here. +** +** To enable these, uncomment them, and place the apropriate +** existing type names in place of the '?' characters. +*/ + +// standard "sized integer" types +// #define int8_t ? +// #define uint8_t ? +// #define int16_t ? +// #define uint16_t ? +// #define int32_t ? +// #define uint32_t ? +// #define int64_t ? +// #define uint64_t ? +// #define bool_t ? + +/* +** Section 2: other types +** +** Add type definitions here as needed. +** +** Note: we do not include the PCB and Queue declarations +** here because we don't actually need them in this header +** file - we're only defining CPP macros. Whatever file +** uses these macros, however, must include the appropriate +** headers if it uses these macros. +** +** To enable these, uncomment them, and place the apropriate +** existing type names in place of the '?' characters. +*/ + +// type name for the PCB +#define PCBTYPE pcb_t + +// type name for our queue +#define QTYPE pcb_queue_t + +/* +** Section 3: interface and behavior +** +** Include #define statements here as needed to define +** the names of functions and globals used in these modules +** in terms of the names used in the rest of the baseline. +** +** To enable these, uncomment them, and place the apropriate +** existing variable or function names in place of the '?' characters. +*/ + +// string functions +#define SLENGTH strlen + +// scheduler +#define SCHED schedule + +// dispatcher +#define DISPATCH dispatch + +/* +** blocked queue for reading processes +** +** Define this if we are blocking processes which try to +** read from the SIO when no characters are available. +** Its value should be the name of the globally-visible +** queue to be used. +*/ +#define QNAME sioread + +#ifdef QNAME + +// Only define these macros if we need to be able to create and +// manage a queue of things. It is expected that these will need +// to be customized based on the names and calling sequences of +// the appropriate functions. + +// invoke the queue creation function +// examples: +// +// #define QCREATE(q) do { +// _que_create( &(q), NULL ); +// } while(0) +// +// #define QCREATE(q) // do nothing + +#define QCREATE(q) // handled elsewhere for us + +// check to see if the queue is empty +// examples: +// +// #define QEMPTY(q) queue_is_empty(q) +// #define QEMPTY(q) (quene_length(q) > 0) +#define QEMPTY(q) pcb_queue_empty(q) + +// this macro expands into code that removes a value from +// 'q' and places it into 'd' +#define QDEQUE(q, d) \ + do { \ + assert(pcb_queue_remove((q), (pcb_t **)&(d)) == SUCCESS); \ + } while (0) + +#endif /* QNAME */ + +#endif diff --git a/kernel/old/include/debug.h b/kernel/old/include/debug.h new file mode 100644 index 0000000..41e38cb --- /dev/null +++ b/kernel/old/include/debug.h @@ -0,0 +1,356 @@ +/** +** @file debug.h +** +** @author Numerous CSCI-452 classes +** +** Debugging macros and constants. +** +*/ + +#ifndef DEBUG_H_ +#define DEBUG_H_ + +// Standard system headers + +#include <cio.h> +#include <support.h> + +// Kernel library + +#include <lib.h> + +#ifndef ASM_SRC + +/* +** Start of C-only definitions +*/ + +/* +** General function entry/exit announcements +*/ + +#ifdef ANNOUNCE_ENTRY +// Announce that we have entered a kernel function +// usage: ENTERING( "name" ), EXITING( "name" ) +// currently, these do not use the macro parameter, but could be +// modified to do so; instead, we use the __func__ CPP pseudo-macro +// to get the function name +#define ENTERING(n) \ + do { \ + cio_puts(" enter " __func__); \ + } while (0) +#define EXITING(n) \ + do { \ + cio_puts(" exit " __func__); \ + } while (0) +#else +#define ENTERING(m) // do nothing +#define EXITING(m) // do nothing +#endif + +/* +** Console messages when error conditions are noted. +*/ + +// Warning messages to the console +// m: message (condition, etc.) +#define WARNING(m) \ + do { \ + cio_printf("\n** %s (%s @ %d): ", __func__, __FILE__, __LINE__); \ + cio_puts(m); \ + cio_putchar('\n'); \ + } while (0) + +// Panic messages to the console +// n: severity level +// m: message (condition, etc.) +#define PANIC(n, m) \ + do { \ + sprint(b512, "%s (%s @ %d), %d: %s\n", __func__, __FILE__, __LINE__, \ + n, #m); \ + kpanic(b512); \ + } while (0) + +/* +** Assertions are categorized by the "sanity level" being used in this +** compilation; each only triggers a fault if the sanity level is at or +** above a specific value. This allows selective enabling/disabling of +** debugging checks. +** +** The sanity level is set during compilation with the CPP macro +** "SANITY". A sanity level of 0 disables conditional assertions, +** but not the basic assert() version. +*/ + +#ifndef SANITY +// default sanity check level: check everything! +#define SANITY 9999 +#endif + +// Always-active assertions +#define assert(x) \ + if (!(x)) { \ + PANIC(0, x); \ + } + +// only provide these macros if the sanity check level is positive + +#if SANITY > 0 + +#define assert1(x) \ + if (SANITY >= 1 && !(x)) { \ + PANIC(1, x); \ + } +#define assert2(x) \ + if (SANITY >= 2 && !(x)) { \ + PANIC(2, x); \ + } +#define assert3(x) \ + if (SANITY >= 3 && !(x)) { \ + PANIC(3, x); \ + } +#define assert4(x) \ + if (SANITY >= 4 && !(x)) { \ + PANIC(4, x); \ + } +// arbitrary sanity level +#define assertN(n, x) \ + if (SANITY >= (n) && !(x)) { \ + PANIC(n, x); \ + } + +#else + +#define assert1(x) // do nothing +#define assert2(x) // do nothing +#define assert3(x) // do nothing +#define assert4(x) // do nothing +#define assertN(n, x) // do nothing + +#endif /* SANITY > 0 */ + +/* +** Tracing options are enabled by defining one or more of the T_ +** macros described in the Makefile. +** +** To add a tracing option: +** +** 1) Pick a short name for it (e.g., "PCB", "VM", ...) +** 2) At the end of this list, add code like this, with "name" +** replaced by your short name, and "nnnnnnnn" replaced by a +** unique bit that will designate this tracing option: +** +** #ifdef T_name +** #define TRname 0xnnnnnnnn +** #else +** #define TRname 0 +** #endif +** +** Use the next bit position following the one in last list entry. +** 3) Add this to the end of the "TRACE" macro definition: +** +** | TRname +** +** 4) In the list of "TRACING_*" macros, add one for your option +** (using a name that might be more descriptive) in the 'then' clause: +** +** #define TRACING_bettername ((TRACE & TRname) != 0) +** +** 5) Also add a "null" version in the 'else' clause: +** +** #define TRACING_bettername 0 +** +** 6) Maybe add your T_name choice to the Makefile with an explanation +** on the off chance you want anyone else to be able to understand +** what it's used for. :-) +** +** We're making CPP work for its pay with this file. +*/ + +// 2^0 bit +#ifdef T_PCB +#define TRPCB 0x00000001 +#else +#define TRPCB 0 +#endif + +#ifdef T_VM +#define TRVM 0x00000002 +#else +#define TRVM 0 +#endif + +#ifdef T_QUE +#define TRQUEUE 0x00000004 +#else +#define TRQUEUE 0 +#endif + +#ifdef T_SCH +#define TRSCHED 0x00000008 +#else +#define TRSCHED 0 +#endif + +// 2^4 bit +#ifdef T_DSP +#define TRDISP 0x00000010 +#else +#define TRDISP 0 +#endif + +#ifdef T_SCALL +#define TRSYSCALLS 0x00000020 +#else +#define TRSYSCALLS 0 +#endif + +#ifdef T_SRET +#define TRSYSRETS 0x00000040 +#else +#define TRSYSRETS 0 +#endif + +#ifdef T_EXIT +#define TREXIT 0x00000080 +#else +#define TREXIT 0 +#endif + +// 2^8 bit +#ifdef T_INIT +#define TRINIT 0x00000100 +#else +#define TRINIT 0 +#endif + +#ifdef T_KM +#define TRKMEM 0x00000200 +#else +#define TRKMEM 0 +#endif + +#ifdef T_KMFR +#define TRKMEM_F 0x00000400 +#else +#define TRKMEM_F 0 +#endif + +#ifdef T_KMIN +#define TRKMEM_I 0x00000800 +#else +#define TRKMEM_I 0 +#endif + +// 2^12 bit +#ifdef T_FORK +#define TRFORK 0x00001000 +#else +#define TRFORK 0 +#endif + +#ifdef T_EXEC +#define TREXEC 0x00002000 +#else +#define TREXEC 0 +#endif + +#ifdef T_SIO +#define TRSIO_STAT 0x00004000 +#else +#define TRSIO_STAT 0 +#endif + +#ifdef T_SIOR +#define TRSIO_RD 0x00008000 +#else +#define TRSIO_RD 0 +#endif + +// 2^16 bit +#ifdef T_SIOW +#define TRSIO_WR 0x00010000 +#else +#define TRSIO_WR 0 +#endif + +#ifdef T_USER +#define TRUSER 0x00020000 +#else +#define TRUSER 0 +#endif + +#ifdef T_ELF +#define TRELF 0x00040000 +#else +#define TRELF 0 +#endif + +// 13 bits remaining for tracing options +// next available bit: 0x00080000 + +#define TRACE \ + (TRDISP | TREXIT | TRINIT | TRKMEM | TRKMEM_F | TRKMEM_I | TRPCB | \ + TRQUEUE | TRSCHED | TREXEC | TRSIO_RD | TRSIO_STAT | TRSIO_WR | TRFORK | \ + TRVM | TRSYSCALLS | TRSYSRETS | TRUSER | TRELF) + +#if TRACE > 0 + +// compile-time expressions for testing trace options +// usage: #if TRACING_thing +#define TRACING_PCB ((TRACE & TRPCB) != 0) +#define TRACING_VM ((TRACE & TRVM) != 0) +#define TRACING_QUEUE ((TRACE & TRQUEUE) != 0) +#define TRACING_SCHED ((TRACE & TRSCHED) != 0) +#define TRACING_DISPATCH ((TRACE & TRDISPATCH) != 0) +#define TRACING_SYSCALLS ((TRACE & TRSYSCALLS) != 0) +#define TRACING_SYSRETS ((TRACE & TRSYSRETS) != 0) +#define TRACING_EXIT ((TRACE & TREXIT) != 0) +#define TRACING_INIT ((TRACE & TRINIT) != 0) +#define TRACING_KMEM ((TRACE & TRKMEM) != 0) +#define TRACING_KMEM_FREELIST ((TRACE & TRKMEM_F) != 0) +#define TRACING_KMEM_INIT ((TRACE & TRKMEM_I) != 0) +#define TRACING_FORK ((TRACE & TRFORK) != 0) +#define TRACING_EXEC ((TRACE & TREXEC) != 0) +#define TRACING_SIO_STAT ((TRACE & TRSIO_STAT) != 0) +#define TRACING_SIO_ISR ((TRACE & TRSIO_ISR) != 0) +#define TRACING_SIO_RD ((TRACE & TRSIO_RD) != 0) +#define TRACING_SIO_WR ((TRACE & TRSIO_WR) != 0) +#define TRACING_USER ((TRACE & TRUSER) != 0) +#define TRACING_ELF ((TRACE & TRELF) != 0) + +// more generic tests +#define TRACING_SOMETHING (TRACE != 0) + +#else + +// TRACE == 0, so just define these all as "false" + +#define TRACING_PCB 0 +#define TRACING_STACK 0 +#define TRACING_QUEUE 0 +#define TRACING_SCHED 0 +#define TRACING_DISPATCH 0 +#define TRACING_SYSCALLS 0 +#define TRACING_SYSRET 0 +#define TRACING_EXIT 0 +#define TRACING_INIT 0 +#define TRACING_KMEM 0 +#define TRACING_KMEM_FREELIST 0 +#define TRACING_KMEM_INIT 0 +#define TRACING_FORK 0 +#define TRACING_EXEC 0 +#define TRACING_SI_STAT 0 +#define TRACING_SIO_ISR 0 +#define TRACING_SIO_RD 0 +#define TRACING_SIO_WR 0 +#define TRACING_USER 0 +#define TRACING_ELF 0 + +#define TRACING_SOMETHING 0 + +#endif /* TRACE */ + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/defs.h b/kernel/old/include/defs.h new file mode 100644 index 0000000..018b14e --- /dev/null +++ b/kernel/old/include/defs.h @@ -0,0 +1,130 @@ +/** +** @file defs.h +** +** @author Warren R. Carithers +** +** @brief Common definitions. +** +** This header file defines things which are neede by all +** parts of the system (OS and user levels). +** +** Things which are kernel-specific go in the kdefs.h file; +** things which are user-specific go in the udefs.h file. +** The correct one of these will be automatically included +** at the end of this file. +*/ + +#ifndef DEFS_H_ +#define DEFS_H_ + +/* +** General (C and/or assembly) definitions +** +** This section of the header file contains definitions that can be +** used in either C or assembly-language source code. +*/ + +// NULL pointer value +// +// we define this the traditional way so that +// it's usable from both C and assembly + +#define NULL 0 + +// predefined i/o channels + +#define CHAN_CIO 0 +#define CHAN_SIO 1 + +// sizes of various things +#define NUM_1KB 0x00000400 // 2^10 +#define NUM_4KB 0x00001000 // 2^12 +#define NUM_1MB 0x00100000 // 2^20 +#define NUM_4MB 0x00400000 // 2^22 +#define NUM_1GB 0x40000000 // 2^30 +#define NUM_2GB 0x80000000 // 2^31 +#define NUM_3GB 0xc0000000 // 1GB + 2GB + +#ifndef ASM_SRC + +/* +** Start of C-only definitions +** +** Anything that should not be visible to something other than +** the C compiler should be put here. +*/ + +/* +** System error codes +** +** These can be returned to both system functions +** and to user system calls. +*/ +// success! +#define SUCCESS (0) +#define E_SUCCESS SUCCESS +// generic "something went wrong" +#define E_FAILURE (-1) +// specific failure reasons +#define E_BAD_PARAM (-2) +#define E_BAD_CHAN (-3) +#define E_NO_CHILDREN (-4) +#define E_NO_MEMORY (-5) +#define E_NOT_FOUND (-6) +#define E_NO_PROCS (-7) + +/* +** These error codes are internal to the OS. +*/ +#define E_EMPTY_QUEUE (-100) +#define E_NO_PCBS (-101) +#define E_NO_PTE (-102) +#define E_LOAD_LIMIT (-103) + +// exit status values +#define EXIT_SUCCESS (0) +#define EXIT_FAILURE (-1) +#define EXIT_KILLED (-101) +#define EXIT_BAD_SYSCALL (-102) + +/* +** Process priority values +*/ +enum priority_e { + PRIO_HIGH, + PRIO_STD, + PRIO_LOW, + PRIO_DEFERRED + // sentinel + , + N_PRIOS +}; + +// halves of various data sizes + +#define UI16_UPPER 0xff00 +#define UI16_LOWER 0x00ff + +#define UI32_UPPER 0xffff0000 +#define UI32_LOWER 0x0000ffff + +#define UI64_UPPER 0xffffffff00000000LL +#define UI64_LOWER 0x00000000ffffffffLL + +// Simple conversion pseudo-functions usable by everyone + +// convert seconds to ms +#define SEC_TO_MS(n) ((n) * 1000) + +#endif /* !ASM_SRC */ + +/* +** Level-specific definitions +*/ +#ifdef KERNEL_SRC +#include <kdefs.h> +#else +#include <udefs.h> +#endif /* KERNEL_SRC */ + +#endif diff --git a/kernel/old/include/kdefs.h b/kernel/old/include/kdefs.h new file mode 100644 index 0000000..d26fa3d --- /dev/null +++ b/kernel/old/include/kdefs.h @@ -0,0 +1,157 @@ +/** +** @file kdefs.h +** +** @author CSCI-452 class of 20245 +** +** @brief Kernel-only declarations. +*/ + +#ifndef KDEFS_H_ +#define KDEFS_H_ + +// debugging macros +#include <debug.h> + +/* +** General (C and/or assembly) definitions +*/ + +// page sizes +#define SZ_PAGE NUM_4KB +#define SZ_BIGPAGE NUM_4MB + +// kernel stack size (bytes) +#define N_KSTKPAGES 1 +#define SZ_KSTACK (N_KSTKPAGES * SZ_PAGE) + +// user stack size +#define N_USTKPAGES 2 +#define SZ_USTACK (N_USTKPAGES * SZ_PAGE) + +// declarations for modulus checking of (e.g.) sizes and addresses + +#define LOW_9_BITS 0x00000fff +#define LOW_22_BITS 0x003fffff +#define HIGH_20_BITS 0xfffff000 +#define HIGH_10_BITS 0xffc00000 + +#define MOD4_BITS 0x00000003 +#define MOD4_MASK 0xfffffffc +#define MOD4_INC 0x00000004 +#define MOD4_SHIFT 2 + +#define MOD16_BITS 0x0000000f +#define MOD16_MASK 0xfffffff0 +#define MOD16_INC 0x00000010 +#define MOD16_SHIFT 4 + +#define MOD1K_BITS 0x000003ff +#define MOD1K_MASK 0xfffffc00 +#define MOD1K_INC 0x00000400 +#define MOD1K_SHIFT 10 + +#define MOD4K_BITS 0x00000fff +#define MOD4K_MASK 0xfffff000 +#define MOD4K_INC 0x00001000 +#define MOD4K_SHIFT 12 + +#define MOD1M_BITS 0x000fffff +#define MOD1M_MASK 0xfff00000 +#define MOD1M_INC 0x00100000 +#define MOD1M_SHIFT 20 + +#define MOD4M_BITS 0x003fffff +#define MOD4M_MASK 0xffc00000 +#define MOD4M_INC 0x00400000 +#define MOD4M_SHIFT 22 + +#define MOD1G_BITS 0x3fffffff +#define MOD1G_MASK 0xc0000000 +#define MOD1G_INC 0x40000000 +#define MOD1G_SHIFT 30 + +#ifndef ASM_SRC + +/* +** Start of C-only definitions +*/ + +// unit conversion macros +#define B_TO_KB(x) (((uint_t)(x)) >> 10) +#define B_TO_MB(x) (((uint_t)(x)) >> 20) +#define B_TO_GB(x) (((uint_t)(x)) >> 30) + +#define KB_TO_B(x) (((uint_t)(x)) << 10) +#define KB_TO_MB(x) (((uint_t)(x)) >> 10) +#define KB_TO_GB(x) (((uint_t)(x)) >> 20) + +#define MB_TO_B(x) (((uint_t)(x)) << 20) +#define MB_TO_KB(x) (((uint_t)(x)) << 10) +#define MB_TO_GB(x) (((uint_t)(x)) >> 10) + +#define GB_TO_B(x) (((uint_t)(x)) << 30) +#define GB_TO_KB(x) (((uint_t)(x)) << 20) +#define GB_TO_MB(x) (((uint_t)(x)) << 10) + +// potetially useful compiler attributes +#define ATTR_ALIGNED(x) __attribute__((__aligned__(x))) +#define ATTR_PACKED __attribute__((__packed__)) +#define ATTR_UNUSED __attribute__((__unused__)) + +/* +** Utility macros +*/ + +// +// macros to clear data structures +// +// these are usable for clearing single-valued data items (e.g., +// a PCB, etc.) +#define CLEAR(v) memclr(&v, sizeof(v)) +#define CLEAR_PTR(p) memclr(p, sizeof(*p)) + +// +// macros for access registers and system call arguments +// + +// REG(pcb,x) -- access a specific register in a process context +#define REG(pcb, x) ((pcb)->context->x) + +// RET(pcb) -- access return value register in a process context +#define RET(pcb) ((pcb)->context->eax) + +// ARG(pcb,n) -- access argument #n from the indicated process +// +// ARG(pcb,0) --> return address +// ARG(pcb,1) --> first parameter +// ARG(pcb,2) --> second parameter +// etc. +// +// ASSUMES THE STANDARD 32-BIT ABI, WITH PARAMETERS PUSHED ONTO THE +// STACK. IF THE PARAMETER PASSING MECHANISM CHANGES, SO MUST THIS! +#define ARG(pcb, n) (((uint32_t *)(((pcb)->context) + 1))[(n)]) + +/* +** Types +*/ + +/* +** Globals +*/ + +// general-purpose character buffer +extern char b256[256]; + +// buffer for use by PANIC() macro +extern char b512[512]; + +// kernel stack +extern uint8_t kstack[SZ_KSTACK]; + +/* +** Prototypes +*/ + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/klib.h b/kernel/old/include/klib.h new file mode 100644 index 0000000..60f59da --- /dev/null +++ b/kernel/old/include/klib.h @@ -0,0 +1,57 @@ +/* +** @file klib.h +** +** @author Warren R. Carithers +** +** Additional support functions for the kernel. +*/ + +#ifndef KLIB_H_ +#define KLIB_H_ + +#include <common.h> + +#ifndef ASM_SRC + +#include <x86/ops.h> + +/** +** Name: put_char_or_code( ch ) +** +** Description: Prints a character on the console, unless it +** is a non-printing character, in which case its hex code +** is printed +** +** @param ch The character to be printed +*/ +void put_char_or_code(int ch); + +/** +** Name: backtrace +** +** Perform a simple stack backtrace. Could be augmented to use the +** symbol table to print function/variable names, etc., if so desired. +** +** @param ebp Initial EBP to use +** @param args Number of function argument values to print +*/ +void backtrace(uint32_t *ebp, uint_t args); + +/** +** Name: kpanic +** +** Kernel-level panic routine +** +** usage: kpanic( msg ) +** +** Prefix routine for panic() - can be expanded to do other things +** (e.g., printing a stack traceback) +** +** @param msg[in] String containing a relevant message to be printed, +** or NULL +*/ +void kpanic(const char *msg); + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/kmem.h b/kernel/old/include/kmem.h new file mode 100644 index 0000000..631f7ab --- /dev/null +++ b/kernel/old/include/kmem.h @@ -0,0 +1,138 @@ +/** +** @file kmem.h +** +** @author Warren R. Carithers +** @author Kenneth Reek +** @author 4003-506 class of 20013 +** +** @brief Support for dynamic memory allocation within the OS. +** +** This is a basic page allocator. Each allocation request returns +** a pointer to a single 4096-byte page of memory. +** +** The module also supports subddivision of pages into "slices", +** each of which is 1KB (i.e., 1/4 of a page). +*/ + +#ifndef KMEM_H_ +#define KMEM_H_ + +#define KERNEL_SRC + +// standard types etc. +#include <common.h> + +/* +** General (C and/or assembly) definitions +*/ + +// Slab and slice sizes, in bytes + +#define SZ_SLAB SZ_PAGE +#define SZ_SLICE (SZ_SLAB >> 2) + +// memory limits +// +// these determine the range of memory addresses the kmem +// module will manage +// +// we won't map any memory below 1MB or above 1GB +#define KM_LOW_CUTOFF NUM_1MB +#define KM_HIGH_CUTOFF NUM_1GB + +#ifndef ASM_SRC + +/* +** Start of C-only definitions +*/ + +/* +** Types +*/ + +/* +** Globals +*/ + +/* +** Prototypes +*/ + +/** +** Name: km_init +** +** Find what memory is present on the system and +** construct the list of free memory blocks. +** +** Dependencies: +** Must be called before any other init routine that uses +** dynamic storage is called. +*/ +void km_init(void); + +/** +** Name: km_dump +** +** Dump information about the free lists to the console. By default, +** prints only the list sizes; if 'addrs' is true, also dumps the list +** of page addresses; if 'all' is also true, dumps page addresses and +** slice addresses. +** +** @param addrs Also dump page addresses +** @param both Also dump slice addresses +*/ +void km_dump(bool_t addrs, bool_t both); + +/* +** Functions that manipulate free memory blocks. +*/ + +/** +** Name: km_page_alloc +** +** Allocate a page of memory from the free list. +** +** @return a pointer to the beginning of the allocated page, +** or NULL if no memory is available +*/ +void *km_page_alloc(void); + +/** +** Name: km_page_free +** +** Returns a memory block to the list of available blocks, +** combining it with adjacent blocks if they're present. +** +** CRITICAL ASSUMPTION: multi-page blocks will be freed one page +** at a time! +** +** @param[in] block Pointer to the page to be returned to the free list +*/ +void km_page_free(void *block); + +/** +** Name: km_slice_alloc +** +** Dynamically allocates a slice (1/4 of a page). If no +** memory is available, we return NULL (unless ALLOC_FAIL_PANIC +** was defined, in which case we panic). +** +** @return a pointer to the allocated slice +*/ +void *km_slice_alloc(void); + +/** +** Name: km_slice_free +** +** Returns a slice to the list of available slices. +** +** We make no attempt to merge slices, as they are independent +** blocks of memory (unlike pages). +** +** @param[in] block Pointer to the slice (1/4 page) to be freed +*/ +void km_slice_free(void *block); + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/list.h b/kernel/old/include/list.h new file mode 100644 index 0000000..0be11e9 --- /dev/null +++ b/kernel/old/include/list.h @@ -0,0 +1,68 @@ +/** +** @file list.h +** +** @author Warren R. Carithers +** +** @brief Support for a basic linked list data type. +** +** This module provides a very basic linked list data structure. +** A list can contain anything that has a pointer field in the first +** four bytes; these routines assume those bytes contain a pointer to +** the following entry in the list, whatever that may be. +*/ + +#ifndef LIST_H_ +#define LIST_H_ + +#define KERNEL_SRC + +// standard types etc. +#include <common.h> + +/* +** General (C and/or assembly) definitions +*/ + +#ifndef ASM_SRC + +/* +** Start of C-only definitions +*/ + +/* +** Data types +*/ + +// The list structure +typedef struct list_s { + struct list_s *next; // link to the successor +} list_t; + +/* +** Prototypes +*/ + +/** +** Name: list_add +** +** Add the supplied data to the beginning of the specified list. +** +** @param[in,out] list The address of a list_t variable +** @param[in] data The data to prepend to the list +*/ +void list_add(list_t *list, void *data); + +/** +** Name: list_remove +** +** Remove the first entry from a linked list. +** +** @param[in,out] list The address of a list_t variable +** +** @return a pointer to the removed data, or NULL if the list was empty +*/ +void *list_remove(list_t *list); + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/params.h b/kernel/old/include/params.h new file mode 100644 index 0000000..7a41e02 --- /dev/null +++ b/kernel/old/include/params.h @@ -0,0 +1,33 @@ +/** +** @file params.h +** +** @author CSCI-452 class of 20245 +** +** @brief System configuration settings +** +** This header file contains many of the "easily tunable" system +** settings, such as clock rate, number of simultaneous user +** processes, etc. This provides a sort of "one-stop shop" for +** things that might be tweaked frequently. +*/ + +#ifndef PARAMS_H_ +#define PARAMS_H_ + +/* +** General (C and/or assembly) definitions +*/ + +// Upper bound on the number of simultaneous user-level +// processes in the system (completely arbitrary) +#define N_PROCS 25 + +// Limit on the number of entries in argv[], INCLUDING +// the trailing NULL pointer (also completely arbitrary) +#define N_ARGS 10 + +// Clock frequency (Hz) +#define CLOCK_FREQ 1000 +#define TICKS_PER_MS 1 + +#endif diff --git a/kernel/old/include/procs.h b/kernel/old/include/procs.h new file mode 100644 index 0000000..bc5b705 --- /dev/null +++ b/kernel/old/include/procs.h @@ -0,0 +1,457 @@ +/* +** @file procs.h +** +** @author CSCI-452 class of 20245 +** +** @brief Process-related declarations +*/ + +#ifndef PROCS_H_ +#define PROCS_H_ + +#include <common.h> + +/* +** General (C and/or assembly) definitions +*/ + +#ifndef ASM_SRC + +/* +** Start of C-only definitions +*/ + +/* +** Types +*/ + +/* +** Process states +*/ +enum state_e { + // pre-viable + STATE_UNUSED = 0, + STATE_NEW, + // runnable + STATE_READY, + STATE_RUNNING, + // runnable, but waiting for some event + STATE_SLEEPING, + STATE_BLOCKED, + STATE_WAITING, + // no longer runnable + STATE_KILLED, + STATE_ZOMBIE + // sentinel value + , + N_STATES +}; + +// these may be handy for checking general conditions of processes +// they depend on the order of the state names in the enum! +#define FIRST_VIABLE STATE_READY +#define FIRST_BLOCKED STATE_SLEEPING +#define LAST_VIABLE STATE_WAITING + +/* +** Process priorities are defined in <defs.h> +*/ + +/* +** Quantum lengths - values are number of clock ticks +*/ +enum quantum_e { QUANTUM_SHORT = 1, QUANTUM_STANDARD = 3, QUANTUM_LONG = 5 }; + +/* +** PID-related definitions +*/ +#define PID_INIT 1 +#define FIRST_USER_PID 2 + +/* +** Process context structure +** +** NOTE: the order of data members here depends on the +** register save code in isr_stubs.S!!!! +** +** This will be at the top of the user stack when we enter +** an ISR. In the case of a system call, it will be followed +** by the return address and the system call parameters. +*/ + +typedef struct context_s { + uint32_t ss; // pushed by isr_save + uint32_t gs; + uint32_t fs; + uint32_t es; + uint32_t ds; + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + uint32_t vector; + uint32_t code; // pushed by isr_save or the hardware + uint32_t eip; // pushed by the hardware + uint32_t cs; + uint32_t eflags; +} context_t; + +#define SZ_CONTEXT sizeof(context_t) + +/* +** program section information for user processes +*/ + +typedef struct section_s { + uint_t length; // length, in some units + uint_t addr; // location, in some units +} section_t; + +// note: these correspond to the PT_LOAD sections found in +// an ELF file, not necessarily to text/data/bss +#define SECT_L1 0 +#define SECT_L2 1 +#define SECT_L3 2 +#define SECT_STACK 3 + +// total number of section table entries in our PCB +#define N_SECTS 4 +// number of those that can be loaded from an ELF module +#define N_LOADABLE 3 + +/* +** The process control block +** +** Fields are ordered by size to avoid padding +** +** Currently, this is 72 bytes long. It could be reduced to 64 (2^6) +** bytes by making the last four fields uint16_t types; that would +** divide nicely into 1024 bytes, giving 16 PCBs per 1/4 page of memory. +*/ + +typedef struct pcb_s { + // four-byte fields + // start with these four bytes, for easy access in assembly + context_t *context; // pointer to context save area on stack + + // VM information + pde_t *pdir; // page directory for this process + section_t sects[N_SECTS]; // per-section memory information + + // queue linkage + struct pcb_s *next; // next PCB in queue + + // process state information + struct pcb_s *parent; // pointer to PCB of our parent process + uint32_t wakeup; // wakeup time, for sleeping processes + int32_t exit_status; // termination status, for parent's use + + // these things may not need to be four bytes + uint_t pid; // PID of this process + enum state_e state; // process' current state + enum priority_e priority; // process priority level + uint_t ticks; // remaining ticks in this time slice + +} pcb_t; + +#define SZ_PCB sizeof(pcb_t) + +/* +** PCB queue structure (opaque to the rest of the kernel) +*/ +typedef struct pcb_queue_s *pcb_queue_t; + +/* +** Queue ordering methods +*/ +enum pcb_queue_order_e { + O_FIFO, + O_PRIO, + O_PID, + O_WAKEUP + // sentinel + , + N_ORDERINGS +}; +#define O_FIRST_STYLE O_FIFO +#define O_LAST_STYLE O_WAKEUP + +/* +** Globals +*/ + +// public-facing queue handles +extern pcb_queue_t pcb_freelist; +extern pcb_queue_t ready; +extern pcb_queue_t waiting; +extern pcb_queue_t sleeping; +extern pcb_queue_t zombie; +extern pcb_queue_t sioread; + +// pointer to the currently-running process +extern pcb_t *current; + +// the process table +extern pcb_t ptable[N_PROCS]; + +// next available PID +extern uint_t next_pid; + +// pointer to the PCB for the 'init' process +extern pcb_t *init_pcb; + +// table of state name strings +extern const char state_str[N_STATES][4]; + +// table of priority name strings +extern const char prio_str[N_PRIOS][5]; + +// table of queue ordering name strings +extern const char ord_str[N_ORDERINGS][5]; + +/* +** Prototypes +*/ + +/** +** Name: pcb_init +** +** Initialization for the Process module. +*/ +void pcb_init(void); + +/** +** Name: pcb_alloc +** +** Allocate a PCB from the list of free PCBs. +** +** @param pcb Pointer to a pcb_t * where the PCB pointer will be returned. +** +** @return status of the allocation attempt +*/ +int pcb_alloc(pcb_t **pcb); + +/** +** Name: pcb_free +** +** Return a PCB to the list of free PCBs. +** +** @param pcb Pointer to the PCB to be deallocated. +*/ +void pcb_free(pcb_t *pcb); + +/** +** Name: pcb_zombify +** +** Turn the indicated process into a Zombie. This function +** does most of the real work for exit() and kill() calls. +** Is also called from the scheduler and dispatcher. +** +** @param pcb Pointer to the newly-undead PCB +*/ +void pcb_zombify(register pcb_t *victim); + +/** +** Name: pcb_cleanup +** +** Reclaim a process' data structures +** +** @param pcb The PCB to reclaim +*/ +void pcb_cleanup(pcb_t *pcb); + +/** +** Name: pcb_find_pid +** +** Locate the PCB for the process with the specified PID +** +** @param pid The PID to be located +** +** @return Pointer to the PCB, or NULL +*/ +pcb_t *pcb_find_pid(uint_t pid); + +/** +** Name: pcb_find_ppid +** +** Locate the PCB for the process with the specified parent +** +** @param pid The PID to be located +** +** @return Pointer to the PCB, or NULL +*/ +pcb_t *pcb_find_ppid(uint_t pid); + +/** +** Name: pcb_queue_reset +** +** Initialize a PCB queue. +** +** @param queue[out] The queue to be initialized +** @param order[in] The desired ordering for the queue +** +** @return status of the init request +*/ +int pcb_queue_reset(pcb_queue_t queue, enum pcb_queue_order_e style); + +/** +** Name: pcb_queue_empty +** +** Determine whether a queue is empty. Essentially just a wrapper +** for the PCB_QUEUE_EMPTY() macro, for use outside this module. +** +** @param[in] queue The queue to check +** +** @return true if the queue is empty, else false +*/ +bool_t pcb_queue_empty(pcb_queue_t queue); + +/** +** Name: pcb_queue_length +** +** Return the count of elements in the specified queue. +** +** @param[in] queue The queue to check +** +** @return the count (0 if the queue is empty) +*/ +uint_t pcb_queue_length(const pcb_queue_t queue); + +/** +** Name: pcb_queue_insert +** +** Inserts a PCB into the indicated queue. +** +** @param queue[in,out] The queue to be used +** @param pcb[in] The PCB to be inserted +** +** @return status of the insertion request +*/ +int pcb_queue_insert(pcb_queue_t queue, pcb_t *pcb); + +/** +** Name: pcb_queue_peek +** +** Return the first PCB from the indicated queue, but don't +** remove it from the queue +** +** @param queue[in] The queue to be used +** +** @return the PCB pointer, or NULL if the queue is empty +*/ +pcb_t *pcb_queue_peek(const pcb_queue_t queue); + +/** +** Name: pcb_queue_remove +** +** Remove the first PCB from the indicated queue. +** +** @param queue[in,out] The queue to be used +** @param pcb[out] Pointer to where the PCB pointer will be saved +** +** @return status of the removal request +*/ +int pcb_queue_remove(pcb_queue_t queue, pcb_t **pcb); + +/** +** Name: pcb_queue_remove_this +** +** Remove the specified PCB from the indicated queue. +** +** @param queue[in,out] The queue to be used +** @param pcb[in] Pointer to the PCB to be removed +** +** @return status of the removal request +*/ +int pcb_queue_remove_this(pcb_queue_t queue, pcb_t *pcb); + +/* +** Scheduler routines +*/ + +/** +** schedule(pcb) +** +** Schedule the supplied process +** +** @param pcb Pointer to the PCB of the process to be scheduled +*/ +void schedule(pcb_t *pcb); + +/** +** dispatch() +** +** Select the next process to receive the CPU +*/ +void dispatch(void); + +/* +** Debugging/tracing routines +*/ + +/** +** Name: ctx_dump +** +** Dumps the contents of this process context to the console +** +** @param msg[in] An optional message to print before the dump +** @param c[in] The context to dump out +*/ +void ctx_dump(const char *msg, register context_t *c); + +/** +** Name: ctx_dump_all +** +** dump the process context for all active processes +** +** @param msg[in] Optional message to print +*/ +void ctx_dump_all(const char *msg); + +/** +** Name: pcb_dump +** +** Dumps the contents of this PCB to the console +** +** @param msg[in] An optional message to print before the dump +** @param p[in] The PCB to dump +** @param all[in] Dump all the contents? +*/ +void pcb_dump(const char *msg, register pcb_t *p, bool_t all); + +/** +** Name: pcb_queue_dump +** +** Dump the contents of the specified queue to the console +** +** @param msg[in] An optional message to print before the dump +** @param queue[in] The queue to dump +** @param contents[in] Also dump (some) contents? +*/ +void pcb_queue_dump(const char *msg, pcb_queue_t queue, bool_t contents); + +/** +** Name: ptable_dump +** +** dump the contents of the "active processes" table +** +** @param msg[in] Optional message to print +** @param all[in] Dump all or only part of the relevant data +*/ +void ptable_dump(const char *msg, bool_t all); + +/** +** Name: ptable_dump_counts +** +** Prints basic information about the process table (number of +** entries, number with each process state, etc.). +*/ +void ptable_dump_counts(void); + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/serial.h b/kernel/old/include/serial.h new file mode 100644 index 0000000..20bf192 --- /dev/null +++ b/kernel/old/include/serial.h @@ -0,0 +1,3 @@ +#pragma once + +#include <stdint.h> diff --git a/kernel/old/include/sio.h b/kernel/old/include/sio.h new file mode 100644 index 0000000..629fda2 --- /dev/null +++ b/kernel/old/include/sio.h @@ -0,0 +1,168 @@ +/** +** @file sio.h +** +** @author Warren R. Carithers +** +** @brief SIO definitions +*/ + +#ifndef SIO_H_ +#define SIO_H_ + +// compatibility definitions +#include <compat.h> + +/* +** General (C and/or assembly) definitions +*/ + +// sio interrupt settings + +#define SIO_TX 0x01 +#define SIO_RX 0x02 +#define SIO_BOTH (SIO_TX | SIO_RX) + +#ifndef ASM_SRC + +/* +** Start of C-only definitions +*/ + +#include <common.h> + +#include <procs.h> + +/* +** PUBLIC GLOBAL VARIABLES +*/ + +// queue for read-blocked processes +extern QTYPE QNAME; + +/* +** PUBLIC FUNCTIONS +*/ + +/** +** sio_init() +** +** Initialize the UART chip. +*/ +void sio_init(void); + +/** +** sio_enable() +** +** Enable SIO interrupts +** +** usage: uint8_t old = sio_enable( uint8_t which ) +** +** @param which Bit mask indicating which interrupt(s) to enable +** +** @return the prior IER setting +*/ +uint8_t sio_enable(uint8_t which); + +/** +** sio_disable() +** +** Disable SIO interrupts +** +** usage: uint8_t old = sio_disable( uint8_t which ) +** +** @param which Bit mask indicating which interrupt(s) to disable +** +** @return the prior IER setting +*/ +uint8_t sio_disable(uint8_t which); + +/** +** sio_inq_length() +** +** Get the input queue length +** +** usage: int num = sio_inq_length() +** +** @return the count of characters still in the input queue +*/ +int sio_inq_length(void); + +/** +** sio_readc() +** +** Get the next input character +** +** usage: int ch = sio_readc() +** +** @return the next character, or -1 if no character is available +*/ +int sio_readc(void); + +/** +** sio_read() +** +** Read the entire input buffer into a user buffer of a specified size +** +** usage: int num = sio_read( char *buffer, int length ) +** +** @param buf The destination buffer +** @param length Length of the buffer +** +** @return the number of bytes copied, or 0 if no characters were available +*/ +int sio_read(char *buffer, int length); + +/** +** sio_writec( ch ) +** +** Write a character to the serial output +** +** usage: sio_writec( int ch ) +** +** @param ch Character to be written (in the low-order 8 bits) +*/ +void sio_writec(int ch); + +/** +** sio_write( ch ) +** +** Write a buffer of characters to the serial output +** +** usage: int num = sio_write( const char *buffer, int length ) +** +** @param buffer Buffer containing characters to write +** @param length Number of characters to write +** +** @return the number of characters copied into the SIO output buffer +*/ +int sio_write(const char *buffer, int length); + +/** +** sio_puts( buf ) +** +** Write a NUL-terminated buffer of characters to the serial output +** +** usage: n = sio_puts( const char *buffer ); +** +** @param buffer The buffer containing a NUL-terminated string +** +** @return the count of bytes transferred +*/ +int sio_puts(const char *buffer); + +/** +** sio_dump( full ) +** +** Dump the contents of the SIO buffers to the console +** +** usage: sio_dump(true) or sio_dump(false) +** +** @param full Boolean indicating whether or not a "full" dump +** is being requested (which includes the contents +** of the queues) +*/ +void sio_dump(bool_t full); + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/support.h b/kernel/old/include/support.h new file mode 100644 index 0000000..ac75a64 --- /dev/null +++ b/kernel/old/include/support.h @@ -0,0 +1,86 @@ +/** +** SCCS ID: @(#)support.h 2.3 1/22/25 +** +** @file support.h +** +** @author K. Reek +** @author Warren R. Carithers +** +** Declarations for functions provided in support.c, and +** some hardware characteristics needed in the initialization. +** +*/ + +#ifndef SUPPORT_H +#define SUPPORT_H + +/* +** Delay values +** +** Notes: The parameter to the delay() function is ambiguous; it +** purports to indicate a delay length, but that isn't really tied +** to any real-world time measurement. +** +** On the original systems we used (dual 500MHz Intel P3 CPUs), each +** "unit" was approximately one tenth of a second, so delay(10) would +** delay for about one second. +** +** On the current machines (Intel Core i5-7500), delay(100) is about +** 2.5 seconds, so each "unit" is roughly 0.025 seconds. +** +** Ultimately, just remember that THESE VALUES ARE APPROXIMATE AT BEST. +*/ +#define DELAY_1_SEC 40 +#define DELAY_1_25_SEC 50 +#define DELAY_2_SEC 80 +#define DELAY_2_5_SEC 100 +#define DELAY_3_SEC 120 +#define DELAY_5_SEC 200 +#define DELAY_7_SEC 280 +#define DELAY_10_SEC 400 + +#ifndef ASM_SRC +/** +** panic +** +** Called when we find an unrecoverable error, this routine disables +** interrupts, prints a description of the error and then goes into a +** hard loop to prevent any further processing. +** +** @param reason NUL-terminated message to be printed. +*/ +void panic(char *reason); + +/** +** init_interrupts +** +** (Re)initilizes the interrupt system. This includes initializing the +** IDT and the PIC. It is up to the user to enable processor interrupts +** when they're ready. +*/ +void init_interrupts(void); + +/* +** install_isr +** +** Installs a second-level handler for a specific interrupt. Returns the +** previously-installed handler for reinstallation (if desired). +** +** @param vector the interrupt vector number +** @param handler the second-stage ISR function to be called by the stub +** +** @return a pointer to the previously-registered ISR +*/ +void (*install_isr(int vector, void (*handler)(int, int)))(int, int); + +/* +** Name: delay +** +** See the comment above about the relative accuracy of the 'length' +** parameter. +*/ +void delay(int length); + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/syscalls.h b/kernel/old/include/syscalls.h new file mode 100644 index 0000000..27392a1 --- /dev/null +++ b/kernel/old/include/syscalls.h @@ -0,0 +1,80 @@ +/** +** @file syscalls.h +** +** @author CSCI-452 class of 20245 +** +** @brief System call declarations +*/ + +#ifndef SYSCALLS_H_ +#define SYSCALLS_H_ + +#include <common.h> + +/* +** General (C and/or assembly) definitions +*/ + +/* +** system call codes +** +** these are used in the user-level C library stub functions, +** and are defined here as CPP macros instead of as an enum +** so that they can be used from assembly +*/ + +#define SYS_exit 0 +#define SYS_waitpid 1 +#define SYS_fork 2 +#define SYS_exec 3 +#define SYS_read 4 +#define SYS_write 5 +#define SYS_getpid 6 +#define SYS_getppid 7 +#define SYS_gettime 8 +#define SYS_getprio 9 +#define SYS_setprio 10 +#define SYS_kill 11 +#define SYS_sleep 12 + +// UPDATE THIS DEFINITION IF MORE SYSCALLS ARE ADDED! +#define N_SYSCALLS 13 + +// dummy system call code for testing our ISR +#define SYS_bogus 0xbad + +// interrupt vector entry for system calls +#define VEC_SYSCALL 0x80 + +#ifndef ASM_SRC + +/* +** Start of C-only definitions +*/ + +/* +** Types +*/ + +/* +** Globals +*/ + +/* +** Prototypes +*/ + +#ifdef KERNEL_SRC + +/** +** Name: sys_init +** +** Syscall module initialization routine +*/ +void sys_init(void); + +#endif /* KERNEL_SRC */ + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/types.h b/kernel/old/include/types.h new file mode 100644 index 0000000..9435954 --- /dev/null +++ b/kernel/old/include/types.h @@ -0,0 +1,13 @@ +#ifndef TYPES_H_ +#define TYPES_H_ +#ifndef ASM_SRC + +#ifdef KERNEL_SRC +// we define these here instead of in vm.h in order to get around a +// nasty chick/egg dependency between procs.h and vm.h +typedef uint32_t pde_t; // page directory entry +typedef uint32_t pte_t; // page table entry +#endif /* KERNEL_SRC */ + +#endif +#endif diff --git a/kernel/old/include/user.h b/kernel/old/include/user.h new file mode 100644 index 0000000..672f916 --- /dev/null +++ b/kernel/old/include/user.h @@ -0,0 +1,139 @@ +/** +** @file user.h +** +** @author CSCI-452 class of 20245 +** +** @brief Declarations of user-level code management routines +*/ + +#ifndef USER_H_ +#define USER_H_ + +#include <common.h> + +#include <procs.h> +#include <x86/arch.h> + +// default value for EFLAGS in new processes +#define DEFAULT_EFLAGS (EFL_MB1 | EFL_IF) + +/* +** General (C and/or assembly) definitions +*/ + +#ifndef ASM_SRC + +/* +** Start of C-only definitions +*/ + +/* +** Types +*/ + +/* +** Blob file organization +** +** The file begins with a four-byte magic number and a four-byte integer +** indicating the number of ELF files contained in the blob. This is +** followed by an array of 32-byte file table entries, and then the contents +** of the ELF files in the order they appear in the program file table. +** +** Bytes Contents +** ----- ---------------------------- +** 0 - 3 File magic number ("BLB\0") +** 4 - 7 Number of ELF files in blob ("n") +** 8 - n*32+8 Program file table +** n*32+9 - ? ELF file contents +** +** Each program file table entry contains the following information: +** +** name File name (up to 19 characters long) +** offset Byte offset to the ELF header for this file +** size Size of this ELF file, in bytes +** flags Flags related to this file +*/ + +// user program blob header +typedef struct header_s { + char magic[4]; + uint32_t num; +} header_t; + +// length of the file name field +#define NAMELEN 20 + +// program descriptor +typedef struct prog_s { + char name[NAMELEN]; // truncated name (15 chars) + uint32_t offset; // offset from the beginning of the blob + uint32_t size; // size of this ELF module + uint32_t flags; // miscellaneous flags +} prog_t; + +/* +** Globals +*/ + +/* +** Prototypes +*/ + +/** +** Name: user_init +** +** Initializes the user support module. +*/ +void user_init(void); + +/** +** Name: user_locate +** +** Locates a user program in the user code archive. +** +** @param what The ID of the user program to find +** +** @return pointer to the program table entry in the code archive, or NULL +*/ +prog_t *user_locate(uint_t what); + +/** +** Name: user_duplicate +** +** Duplicates the memory setup for an existing process. +** +** @param new The PCB for the new copy of the program +** @param old The PCB for the existing the program +** +** @return the status of the duplicate attempt +*/ +int user_duplicate(pcb_t *new, pcb_t *old); + +/** +** Name: user_load +** +** Loads a user program from the user code archive into memory. +** Allocates all needed frames and sets up the VM tables. +** +** @param prog A pointer to the program table entry to be loaded +** @param pcb The PCB for the program being loaded +** @param args The argument vector for the program +** @param sys Is the argument vector from kernel code? +** +** @return the status of the load attempt +*/ +int user_load(prog_t *prog, pcb_t *pcb, const char **args, bool_t sys); + +/** +** Name: user_cleanup +** +** "Unloads" a user program. Deallocates all memory frames and +** cleans up the VM structures. +** +** @param pcb The PCB of the program to be cleaned up +*/ +void user_cleanup(pcb_t *pcb); + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/vm.h b/kernel/old/include/vm.h new file mode 100644 index 0000000..dc12568 --- /dev/null +++ b/kernel/old/include/vm.h @@ -0,0 +1,501 @@ +/** +** @file vm.h +** +** @author CSCI-452 class of 20245 +** +** @brief Virtual memory-related declarations. +*/ + +#ifndef VM_H_ +#define VM_H_ + +#include <defs.h> +#include <types.h> + +#include <procs.h> + +/* +** VM layout of the system +** +** User processes use the first 4MB of the 32-bit address space; see the +** next comment for details. +** +** Kernel virtual addresses are in the "higher half" range, beginning +** at 0x80000000. We define our mapping such that virtual address +** 0x8nnnnnnn maps to physical address 0x0nnnnnnn, so converting between +** the two is trivial. +*/ + +/* +** VM layout of process' address space +** +** Processes are limited to the first 4MB of the 32-bit address space: +** +** Address Range Contents +** ======================= ================================ +** 0x00000000 - 0x00000fff page 0 is inaccessible +** 0x00001000 - 0x000..fff text occupies pages 1 - N +** 0x000..000 - 0x000..fff data occupies pages N+1 - N+d +** 0x000..000 - 0x000..fff bss occupies pages N+d+1 - N+d+b +** 0x000..000 - 0x003fdfff unusable +** 0x003fe000 - 0x003fffff stack occupies last two pages +** +** This gives us the following page table structure: +** +** Page directory: +** Entries Contents +** ======== ============================== +** 0 point to PMT for address space +** 1 - 1023 invalid +** +** Page map table: +** Entries Contents +** ======== ============================== +** 0 invalid +** 1 - N text frames +** N+1 - N+d data frames +** N+d+1 - N+d+b bss frames +** N+d+b+1 - 1021 invalid +** 1022 - 1023 stack frames +*/ + +/* +** General (C and/or assembly) definitions +*/ + +// user virtual addresses +#define USER_BASE 0x00000000 +#define USER_MAX 0x003fffff +#define USER_TEXT 0x00001000 +#define USER_STACK 0x003fe000 +#define USER_STACK_P1 USER_STACK +#define USER_STACK_P2 0x003ff000 +#define USER_STK_END 0x00400000 + +// how to find the addresses of the stack pages in the VM hierarchy +// user address space is the first 4MB of virtual memory +#define USER_PDE 0 +// the stack occupies this range of pages in the user address space +#define USER_STK_FIRST_PTE 1022 +#define USER_STK_LAST_PTE 1023 + +// some important memory addresses +#define KERN_BASE 0x80000000 // start of "kernel" memory +#define EXT_BASE 0x00100000 // start of "extended" memory (1MB) +#define DEV_BASE 0xfe000000 // "device" memory +#define PHYS_TOP 0x3fffffff // last usable physical address (1GB - 1) + +// where the kernel actually lives +#define KERN_PLINK 0x00010000 +#define KERN_VLINK (KERN_BASE + KERN_PLINK) + +// number of entries in a page directory or page table +#define N_PDE 1024 +#define N_PTE 1024 + +// index field shift counts and masks +#define PDIX_SHIFT 22 +#define PTIX_SHIFT 12 +#define PIX2I_MASK 0x3ff + +// physical/virtual converters that don't use casting +// (usable from anywhere) +#define V2PNC(a) ((a) - KERN_BASE) +#define P2VNC(a) ((a) + KERN_BASE) + +// page-size address rounding macros +#define SZ_PG_M1 MOD4K_BITS +#define SZ_PG_MASK MOD4K_MASK +#define PGUP(a) (((a) + SZ_PG_M1) & SZ_PG_MASK) +#define PGDOWN(a) ((a) & SZ_PG_MASK) + +// page directory entry bit fields +#define PDE_P 0x00000001 // 1 = present +#define PDE_RW 0x00000002 // 1 = writable +#define PDE_US 0x00000004 // 1 = user and system usable +#define PDE_PWT 0x00000008 // cache: 1 = write-through +#define PDE_PCD 0x00000010 // cache: 1 = disabled +#define PDE_A 0x00000020 // accessed +#define PDE_D 0x00000040 // dirty (4MB pages) +#define PDE_AVL1 0x00000040 // ignored (4KB pages) +#define PDE_PS 0x00000080 // 1 = 4MB page size +#define PDE_G 0x00000100 // global +#define PDE_AVL2 0x00000e00 // ignored +#define PDE_PAT 0x00001000 // (4MB pages) use page attribute table +#define PDE_PTA 0xfffff000 // page table address field (4KB pages) +#define PDE_FA 0xffc00000 // frame address field (4MB pages) + +// page table entry bit fields +#define PTE_P 0x00000001 // present +#define PTE_RW 0x00000002 // 1 = writable +#define PTE_US 0x00000004 // 1 = user and system usable +#define PTE_PWT 0x00000008 // cache: 1 = write-through +#define PTE_PCD 0x00000010 // cache: 1 = disabled +#define PTE_A 0x00000020 // accessed +#define PTE_D 0x00000040 // dirty +#define PTE_PAT 0x00000080 // use page attribute table +#define PTE_G 0x00000100 // global +#define PTE_AVL2 0x00000e00 // ignored +#define PTE_FA 0xfffff000 // frame address field + +// error code bit assignments for page faults +#define PFLT_P 0x00000001 +#define PFLT_W 0x00000002 +#define PFLT_US 0x00000004 +#define PFLT_RSVD 0x00000008 +#define PFLT_ID 0x00000010 +#define PFLT_PK 0x00000020 +#define PFLT_SS 0x00000040 +#define PFLT_HLAT 0x00000080 +#define PFLT_SGX 0x00008000 +#define PFLT_UNUSED 0xffff7f00 + +#ifndef ASM_SRC + +/* +** Start of C-only definitions +*/ + +// physical/virtual converters that do use casting +// (not usable from assembly) +#define V2P(a) (((uint32_t)(a)) - KERN_BASE) +#define P2V(a) (((uint32_t)(a)) + KERN_BASE) + +// create a pde/pte from an integer frame number and permission bits +#define MKPDE(f, p) ((pde_t)(TO_FRAME((f)) | (p))) +#define MKPTE(f, p) ((pte_t)(TO_FRAME((f)) | (p))) + +// is a PDE/PTE present? +// (P bit is in the same place in both) +#define IS_PRESENT(entry) (((entry) & PDE_P) != 0) + +// is a PDE a 4MB page entry? +#define IS_LARGE(pde) (((pde) & PDE_PS) != 0) + +// is this entry "system only" or "system and user"? +#define IS_SYSTEM(entry) (((entry) & PDE_US) == 0) +#define IS_USER(entry) (((entry) & PDE_US) != 0) + +// low-order nine bits of PDEs and PTEs hold "permission" flag bits +#define PERMS_MASK MOD4K_BITS + +// 4KB frame numbers are 20 bits wide +#define FRAME_4K_SHIFT 12 +#define FRAME2I_4K_MASK 0x000fffff +#define TO_4KFRAME(n) (((n) & FRAME2I_4K_MASK) << FRAME_4K_SHIFT) +#define GET_4KFRAME(n) (((n) >> FRAME_4K_SHIFT) & FRAME2I_4K_MASK) +#define PDE_4K_ADDR(n) ((n) & MOD4K_MASK) +#define PTE_4K_ADDR(n) ((n) & MOD4K_MASK) + +// 4MB frame numbers are 10 bits wide +#define FRAME_4M_SHIFT 22 +#define FRAME2I_4M_MASK 0x000003ff +#define TO_4MFRAME(n) (((n) & FRAME2I_4M_MASK) << FRAME_4M_SHIFT) +#define GET_4MFRAME(n) (((n) >> FRAME_4M_SHIFT) & FRAME2I_4M_MASK) +#define PDE_4M_ADDR(n) ((n) & MOD4M_MASK) +#define PTE_4M_ADDR(n) ((n) & MOD4M_MASK) + +// extract the PMT address or frame address from a table entry +// PDEs could point to 4MB pages, or 4KB PMTs +#define PDE_ADDR(p) \ + (IS_LARGE(p) ? (((uint32_t)p) & PDE_FA) : (((uint32_t)p) & PDE_PTA)) +// PTEs always point to 4KB pages +#define PTE_ADDR(p) (((uint32_t)(p)) & PTE_FA) +// everything has nine bits of permission flags +#define PERMS(p) (((uint32_t)(p)) & PERMS_MASK) + +// extract the table indices from a 32-bit VA +#define PDIX(v) ((((uint32_t)(v)) >> PDIX_SHIFT) & PIX2I_MASK) +#define PTIX(v) ((((uint32_t)(v)) >> PTIX_SHIFT) & PIX2I_MASK) + +// extract the byte offset from a 32-bit VA +#define OFFSET_4K(v) (((uint32_t)(v)) & MOD4K_BITS) +#define OFFSET_4M(v) (((uint32_t)(v)) & MOD4M_BITS) + +/* +** Types +*/ + +// page directory entries + +// as a 32-bit word, in types.h +// typedef uint32_t pde_t; + +// PDE for 4KB pages +typedef struct pdek_s { + uint_t p : 1; // 0: present + uint_t rw : 1; // 1: writable + uint_t us : 1; // 2: user/supervisor + uint_t pwt : 1; // 3: cache write-through + uint_t pcd : 1; // 4: cache disable + uint_t a : 1; // 5: accessed + uint_t avl1 : 1; // 6: ignored (available) + uint_t ps : 1; // 7: page size (must be 0) + uint_t avl2 : 4; // 11-8: ignored (available) + uint_t fa : 20; // 31-12: frame address +} pdek_f_t; + +// PDE for 4MB pages +typedef struct pdem_s { + uint_t p : 1; // 0: present + uint_t rw : 1; // 1: writable + uint_t us : 1; // 2: user/supervisor + uint_t pwt : 1; // 3: cache write-through + uint_t pcd : 1; // 4: cache disable + uint_t a : 1; // 5: accessed + uint_t d : 1; // 6: dirty + uint_t ps : 1; // 7: page size (must be 1) + uint_t g : 1; // 8: global + uint_t avl : 3; // 11-9: ignored (available) + uint_t pat : 1; // 12: page attribute table in use + uint_t fa2 : 4; // 16-13: bits 35-32 of frame address (36-bit addrs) + uint_t rsv : 5; // 21-17: reserved - must be zero + uint_t fa : 10; // 31-22: bits 31-22 of frame address +} pdem_f_t; + +// page table entries + +// as a 32-bit word, in types.h +// typedef uint32_t pte_t; + +// broken out into fields +typedef struct pte_s { + uint_t p : 1; // 0: present + uint_t rw : 1; // 1: writable + uint_t us : 1; // 2: user/supervisor + uint_t pwt : 1; // 3: cache write-through + uint_t pcd : 1; // 4: cache disable + uint_t a : 1; // 5: accessed + uint_t d : 1; // 6: dirty + uint_t pat : 1; // 7: page attribute table in use + uint_t g : 1; // 8: global + uint_t avl : 3; // 11-9: ignored (available) + uint_t fa : 20; // 31-12: frame address +} ptef_t; + +// page fault error code bits +// comment: meaning when 1 / meaning when 0 +struct pfec_s { + uint_t p : 1; // page-level protection violation / !present + uint_t w : 1; // write / read + uint_t us : 1; // user-mode access / supervisor-mode access + uint_t rsvd : 1; // reserved bit violation / not + uint_t id : 1; // instruction fetch / data fetch + uint_t pk : 1; // protection-key violation / !pk + uint_t ss : 1; // shadow stack access / !ss + uint_t hlat : 1; // HLAT paging / ordinary paging or access rights + uint_t xtr1 : 7; // unused + uint_t sgz : 1; // SGX-specific access control violation / !SGX + uint_t xtr2 : 16; // more unused +}; + +typedef union pfec_u { + uint32_t u; + struct pfec_s s; +} pfec_t; + +// Mapping descriptor for VA::PA mappings +typedef struct mapping_t { + uint32_t va_start; // starting virtual address for this range + uint32_t pa_start; // first physical address in the range + uint32_t pa_end; // last physical address in the range + uint32_t perm; // access control +} mapping_t; + +// Modes for dumping out page hierarchies +enum vmmode_e { + Simple = 0, // just count 'present' entries at each level + OneLevel, // top-level only: count entries, decode 'present' + TwoLevel, // count entries & decode at each level + Full // ??? in case we need more? + // sentinel + , + N_VMMODES +}; + +/* +** Globals +*/ + +// created page directory for the kernel +extern pde_t *kpdir; + +/* +** Prototypes +*/ + +/** +** Name: vm_init +** +** Initialize the VM module +** +** Note: should not be called until after the memory free list has +** been set up. +*/ +void vm_init(void); + +/** +** Name: vm_uva2kva +** +** Convert a user VA into a kernel address. Works for all addresses - +** if the address is a page address, the low-order nine bits will be +** zeroes; otherwise, they is the offset into the page, which is +** unchanged within the address spaces. +** +** @param pdir Pointer to the page directory to examine +** @param va Virtual address to check +*/ +void *vm_uva2kva(pde_t *pdir, void *va); + +/** +** Name: vm_pagedup +** +** Duplicate a page of memory +** +** @param old Pointer to the first byte of a page +** +** @return a pointer to the new, duplicate page, or NULL +*/ +void *vm_pagedup(void *old); + +/** +** Name: vm_pdedup +** +** Duplicate a page directory entry +** +** @param entry The entry to be duplicated +** +** @return the new entry, or -1 on error. +*/ +pde_t vm_pdedup(pde_t entry); + +/** +** Name: vm_ptdup +** +** Duplicate a page directory entry +** +** @param dst Pointer to where the duplicate should go +** @param curr Pointer to the entry to be duplicated +** +** @return true on success, else false +*/ +bool_t vm_ptdup(pde_t *dst, pde_t *curr); + +/** +** Name: vm_getpte +** +** Return the address of the PTE corresponding to the virtual address +** 'va' within the address space controlled by 'pgdir'. If there is no +** page table for that VA and 'alloc' is true, create the necessary +** page table entries. +** +** @param pdir Pointer to the page directory to be searched +** @param va The virtual address we're looking for +** @param alloc Should we allocate a page table if there isn't one? +** +** @return A pointer to the page table entry for this VA, or NULL +*/ +pte_t *vm_getpte(pde_t *pdir, const void *va, bool_t alloc); + +/** +** Name: vm_mkkvm +** +** Create the kernel's page table hierarchy +*/ +pde_t *vm_mkkvm(void); + +/** +** Name: vm_mkuvm +** +** Create the page table hierarchy for a user process +*/ +pde_t *vm_mkuvm(void); + +/** +** Name: vm_set_kvm +** +** Switch the page table register to the kernel's page directory +*/ +void vm_set_kvm(void); + +/** +** Name: vm_set_uvm +** +** Switch the page table register to the page directory for a user process. +** +** @param p The PCB of the user process +*/ +void vm_set_uvm(pcb_t *p); + +/** +** Name: vm_add +** +** Add pages to the page hierarchy for a process, copying data into +** them if necessary. +** +** @param pdir Pointer to the page directory to modify +** @param wr "Writable" flag for the PTE +** @param sys "System" flag for the PTE +** @param va Starting VA of the range +** @param size Amount of physical memory to allocate +** @param data Pointer to data to copy, or NULL +** @param bytes Number of bytes to copy +** +** @return status of the allocation attempt +*/ +int vm_add(pde_t *pdir, bool_t wr, bool_t sys, void *va, uint32_t size, + char *data, uint32_t bytes); + +/** +** Name: vm_free +** +** Deallocate a page table hierarchy and all physical memory frames +** in the user portion. +** +** @param pdir Pointer to the page directory +*/ +void vm_free(pde_t *pdir); + +/* +** Name: vm_map +** +** Create PTEs for virtual addresses starting at 'va' that refer to +** physical addresses in the range [pa, pa+size-1]. We aren't guaranteed +** that va is page-aligned. +** +** @param pdir Page directory for this address space +** @param va The starting virtual address +** @param pa The starting physical address +** @param size Length of the range to be mapped +** @param perm Permission bits for the PTEs +*/ +int vm_map(pde_t *pdir, void *va, uint32_t pa, uint32_t size, int perm); + +/** +** Name: vm_uvmdup +** +** Create a duplicate of the user portio of an existing page table +** hierarchy. We assume that the "new" page directory exists and +** the system portions of it should not be touched. +** +** @param new New page directory +** @param old Existing page directory +** +** @return status of the duplication attempt +*/ +int vm_uvmdup(pde_t *new, pde_t *old); + +/** +** Name: vm_print +** +** Print out a paging hierarchy. +** +** @param pt Page table to display +** @param dir Is it a page directory (vs. a page table)? +** @param mode How to display the entries +*/ +void vm_print(void *pt, bool_t dir, enum vmmode_e mode); + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/vmtables.h b/kernel/old/include/vmtables.h new file mode 100644 index 0000000..83c0881 --- /dev/null +++ b/kernel/old/include/vmtables.h @@ -0,0 +1,43 @@ +/** +** @file vmtables.h +** +** @author CSCI-452 class of 20245 +** +** @brief Predefined VM tables +*/ + +#ifndef VMTABLES_H_ +#define VMTABLES_H_ + +#include <defs.h> +#include <types.h> +#include <vm.h> + +#ifndef ASM_SRC + +/* +** Initial page directory, for when the kernel is starting up +** +** we use large (4MB) pages here to allow us to use a one-level +** paging hierarchy; the kernel will create a new page table +** hierarchy once memory is initialized +*/ +extern pde_t firstpdir[]; + +/* +** "Identity" page map table. +** +** This just maps the first 4MB of physical memory. It is initialized +** in vm_init(). +*/ +extern pte_t id_map[]; + +/* +** Kernel address mappings, present in every page table +*/ +extern mapping_t kmap[]; +extern const uint32_t n_kmap; + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/x86/arch.h b/kernel/old/include/x86/arch.h new file mode 100644 index 0000000..df0b2e2 --- /dev/null +++ b/kernel/old/include/x86/arch.h @@ -0,0 +1,299 @@ +/* +** @file arch.h +** +** @author Warren R. Carithers +** @author K. Reek +** +** Definitions of constants and macros for use +** with the x86 architecture and registers. +** +*/ + +#ifndef X86ARCH_H_ +#define X86ARCH_H_ + +/* +** Video stuff +*/ +#define VID_BASE_ADDR 0xB8000 + +/* +** Memory management +*/ +#define SEG_PRESENT 0x80 +#define SEG_PL_0 0x00 +#define SEG_PL_1 0x20 +#define SEG_PL_2 0x40 +#define SEG_PL_3 0x50 +#define SEG_SYSTEM 0x00 +#define SEG_NON_SYSTEM 0x10 +#define SEG_32BIT 0x04 +#define DESC_IGATE 0x06 + +/* +** Exceptions +*/ +#define N_EXCEPTIONS 256 + +/* +** Bit definitions in registers +** +** See IA-32 Intel Architecture SW Dev. Manual, Volume 3: System +** Programming Guide, page 2-8. +*/ +/* +** EFLAGS +*/ +#define EFL_RSVD 0xffc00000 /* reserved */ +#define EFL_MB0 0x00008020 /* must be zero */ +#define EFL_MB1 0x00000002 /* must be 1 */ + +#define EFL_ID 0x00200000 +#define EFL_VIP 0x00100000 +#define EFL_VIF 0x00080000 +#define EFL_AC 0x00040000 +#define EFL_VM 0x00020000 +#define EFL_RF 0x00010000 +#define EFL_NT 0x00004000 +#define EFL_IOPL 0x00003000 +#define EFL_OF 0x00000800 +#define EFL_DF 0x00000400 +#define EFL_IF 0x00000200 +#define EFL_TF 0x00000100 +#define EFL_SF 0x00000080 +#define EFL_ZF 0x00000040 +#define EFL_AF 0x00000010 +#define EFL_PF 0x00000004 +#define EFL_CF 0x00000001 + +/* +** CR0, CR1, CR2, CR3, CR4 +** +** IA-32 V3, page 2-12. +*/ +#define CR0_RSVD 0x1ffaffc0 +#define CR0_PG 0x80000000 +#define CR0_CD 0x40000000 +#define CR0_NW 0x20000000 +#define CR0_AM 0x00040000 +#define CR0_WP 0x00010000 +#define CR0_NE 0x00000020 +#define CR0_ET 0x00000010 +#define CR0_TS 0x00000008 +#define CR0_EM 0x00000004 +#define CR0_MP 0x00000002 +#define CR0_PE 0x00000001 + +#define CR1_RSVD 0xffffffff + +#define CR2_RSVD 0x00000000 +#define CR2_PF_LIN_ADDR 0xffffffff + +#define CR3_RSVD 0x00000fe7 +#define CR3_PD_BASE 0xfffff000 +#define CR3_PCD 0x00000010 +#define CR3_PWT 0x00000008 + +#define CR4_RSVD 0xfd001000 +#define CR4_UINT 0x02000000 +#define CR4_PKS 0x01000000 +#define CR4_CET 0x00800000 +#define CR4_PKE 0x00400000 +#define CR4_SMAP 0x00200000 +#define CR4_SMEP 0x00100000 +#define CR4_KL 0x00080000 +#define CR4_OSXS 0x00040000 +#define CR4_PCID 0x00020000 +#define CR4_FSGS 0x00010000 +#define CR4_SMXE 0x00004000 +#define CR4_VMXE 0x00002000 +#define CR4_LA57 0x00001000 +#define CR4_UMIP 0x00000800 +#define CR4_OSXMMEXCPT 0x00000400 +#define CR4_OSFXSR 0x00000200 +#define CR4_PCE 0x00000100 +#define CR4_PGE 0x00000080 +#define CR4_MCE 0x00000040 +#define CR4_PAE 0x00000020 +#define CR4_PSE 0x00000010 +#define CR4_DE 0x00000008 +#define CR4_TSD 0x00000004 +#define CR4_PVI 0x00000002 +#define CR4_VME 0x00000001 + +/* +** PMode segment selector field masks +** +** IA-32 V3, page 3-8. +*/ +#define SEG_SEL_IX_MASK 0xfff8 +#define SEG_SEL_TI_MASK 0x0004 +#define SEG_SEL_RPL_MASK 0x0003 + +/* +** Segment descriptor bytes +** +** IA-32 V3, page 3-10. +** +** Bytes: +** 0, 1: segment limit 15:0 +** 2, 3: base address 15:0 +** 4: base address 23:16 +** 7: base address 31:24 +*/ +/* +** Byte 5: access control bits +** 7: present +** 6-5: DPL +** 4: system/user +** 3-0: type +*/ +#define SEG_ACCESS_P_MASK 0x80 +#define SEG_PRESENT 0x80 +#define SEG_NOT_PRESENT 0x00 + +#define SEG_ACCESS_DPL_MASK 0x60 +#define SEG_DPL_0 0x00 +#define SEG_DPL_1 0x20 +#define SEG_DPL_2 0x40 +#define SEG_DPL_3 0x60 + +#define SEG_ACCESS_S_MASK 0x10 +#define SEG_SYSTEM 0x00 +#define SEG_NON_SYSTEM 0x10 + +#define SEG_TYPE_MASK 0x0f +#define SEG_DATA_A_BIT 0x1 +#define SEG_DATA_W_BIT 0x2 +#define SEG_DATA_E_BIT 0x4 +#define SEG_CODE_A_BIT 0x1 +#define SEG_CODE_R_BIT 0x2 +#define SEG_CODE_C_BIT 0x4 +#define SEG_DATA_RO 0x0 +#define SEG_DATA_ROA 0x1 +#define SEG_DATA_RW 0x2 +#define SEG_DATA_RWA 0x3 +#define SEG_DATA_RO_XD 0x4 +#define SEG_DATA_RO_XDA 0x5 +#define SEG_DATA_RW_XW 0x6 +#define SEG_DATA_RW_XWA 0x7 +#define SEG_CODE_XO 0x8 +#define SEG_CODE_XOA 0x9 +#define SEG_CODE_XR 0xa +#define SEG_CODE_XRA 0xb +#define SEG_CODE_XO_C 0xc +#define SEG_CODE_XO_CA 0xd +#define SEG_CODE_XR_C 0xe +#define SEG_CODE_XR_CA 0xf + +/* +** Byte 6: sizes +** 7: granularity +** 6: d/b +** 5: long mode +** 4: available! +** 3-0: upper 4 bits of limit +** 7: base address 31:24 +*/ +#define SEG_SIZE_G_MASK 0x80 +#define SEG_GRAN_BYTE 0x00 +#define SEG_GRAN_4KBYTE 0x80 + +#define SEG_SIZE_D_B_MASK 0x40 +#define SEG_DB_16BIT 0x00 +#define SEG_DB_32BIT 0x40 + +#define SEG_SIZE_L_MASK 0x20 +#define SEG_L_64BIT 0x20 +#define SEG_L_32BIT 0x00 + +#define SEG_SIZE_AVL_MASK 0x10 + +#define SEG_SIZE_LIM_19_16_MASK 0x0f + +/* +** System-segment and gate-descriptor types +** +** IA-32 V3, page 3-15. +*/ +// type 0: reserved +#define SEG_SYS_16BIT_TSS_AVAIL 0x1 +#define SEG_SYS_LDT 0x2 +#define SEG_SYS_16BIT_TSS_BUSY 0x3 +#define SEG_SYS_16BIT_CALL_GATE 0x4 +#define SEG_SYS_TASK_GATE 0x5 +#define SEG_SYS_16BIT_INT_GATE 0x6 +#define SEG_SYS_16BIT_TRAP_GATE 0x7 +// type 8: reserved +#define SEG_SYS_32BIT_TSS_AVAIL 0x9 +// type A: reserved +#define SEG_SYS_32BIT_TSS_BUSY 0xb +#define SEG_SYS_32BIT_CALL_GATE 0xc +// type D: reserved +#define SEG_SYS_32BIT_INT_GATE 0xe +#define SEG_SYS_32BIT_TRAP_GATE 0xf + +/* +** IDT Descriptors +** +** IA-32 V3, page 5-13. +** +** All have a segment selector in bytes 2 and 3; Task Gate descriptors +** have bytes 0, 1, 4, 6, and 7 reserved; others have bytes 0, 1, 6, +** and 7 devoted to the 16 bits of the Offset, with the low nybble of +** byte 4 reserved. +*/ +#define IDT_PRESENT 0x8000 +#define IDT_DPL_MASK 0x6000 +#define IDT_DPL_0 0x0000 +#define IDT_DPL_1 0x2000 +#define IDT_DPL_2 0x4000 +#define IDT_DPL_3 0x6000 +#define IDT_GATE_TYPE 0x0f00 +#define IDT_TASK_GATE 0x0500 +#define IDT_INT16_GATE 0x0600 +#define IDT_INT32_GATE 0x0e00 +#define IDT_TRAP16_GATE 0x0700 +#define IDT_TRAP32_GATE 0x0f00 + +/* +** Interrupt vectors +*/ +// predefined by the architecture +#define VEC_DIVIDE_ERROR 0x00 +#define VEC_DEBUG_EXCEPTION 0x01 +#define VEC_NMI_INTERRUPT 0x02 +#define VEC_BREAKPOINT 0x03 +#define VEC_OVERFLOW 0x04 +#define VEC_BOUND_RANGE_EXCEEDED 0x05 +#define VEC_INVALID_OPCODE 0x06 +#define VEC_DEVICE_NOT_AVAILABLE 0x07 +#define VEC_DOUBLE_FAULT 0x08 +#define VEC_COPROCESSOR_OVERRUN 0x09 +#define VEC_INVALID_TSS 0x0a +#define VEC_SEGMENT_NOT_PRESENT 0x0b +#define VEC_STACK_FAULT 0x0c +#define VEC_GENERAL_PROTECTION 0x0d +#define VEC_PAGE_FAULT 0x0e +// 0x0f is reserved - unused +#define VEC_FPU_ERROR 0x10 +#define VEC_ALIGNMENT_CHECK 0x11 +#define VEC_MACHINE_CHECK 0x12 +#define VEC_SIMD_FP_EXCEPTION 0x13 +#define VEC_VIRT_EXCEPTION 0x14 +#define VEC_CTRL_PROT_EXCEPTION 0x15 +// 0x16 through 0x1f are reserved + +// 0x20 through 0xff are user-defined, non-reserved + +// IRQ0 through IRQ15 will use vectors 0x20 through 0x2f +#define VEC_TIMER 0x20 +#define VEC_KBD 0x21 +#define VEC_COM2 0x23 +#define VEC_COM1 0x24 +#define VEC_PARALLEL 0x25 +#define VEC_FLOPPY 0x26 +#define VEC_MYSTERY 0x27 +#define VEC_MOUSE 0x2c + +#endif diff --git a/kernel/old/include/x86/ops.h b/kernel/old/include/x86/ops.h new file mode 100644 index 0000000..81167a1 --- /dev/null +++ b/kernel/old/include/x86/ops.h @@ -0,0 +1,395 @@ +/** +** @file ops.h +** +** @author Warren R. Carithers +** +** @brief Inline escapes to assembly for efficiency +** +** Inspiration from: +** Martins Mozeiko, https://gist.github.com/mmozeiko/f68ad2546bd6ab953315 +** MIT's xv6, https://github.com/mit-pdos/xv6-public +** +** Note: normally, GCC doesn't inline unless the optimization level is +** over 1. This can be forced by adding +** +** __attribute__((always_inline)) +** +** after the parameter list on each declaration. This is enabled by +** defining the compile-time CPP symbol FORCE_INLINING. +*/ + +#ifndef OPS_H_ +#define OPS_H_ + +#include <common.h> + +#ifndef ASM_SRC + +// control "forced" inlining +#ifdef FORCE_INLINING +#define OPSINLINED __attribute__((always_inline)) +#else +#define OPSINLINED /* no-op */ +#endif /* FORCE_INLINING */ + +/**************************** +** Data movement +****************************/ + +/** +** Block move functions +** +** Variations: movsb(), movsl(), movsq() +** +** Description: Copy from source buffer to destination buffer +** +** @param dst Destination buffer +** @param src Source buffer +** @param len Byte count +*/ +static inline void movsb(void *dst, const void *src, uint32_t len) OPSINLINED +{ + __asm__ __volatile__("cld; rep movsb" + : "+D"(dst), "+S"(src), "+c"(len) + : + : "memory"); +} +static inline void movsw(void *dst, const void *src, uint32_t len) OPSINLINED +{ + __asm__ __volatile__("cld; rep movsw" + : "+D"(dst), "+S"(src), "+c"(len) + : + : "memory"); +} +static inline void movsl(void *dst, const void *src, uint32_t len) OPSINLINED +{ + __asm__ __volatile__("cld; rep movsl" + : "+D"(dst), "+S"(src), "+c"(len) + : + : "memory"); +} +static inline void movsq(void *dst, const void *src, uint32_t len) OPSINLINED +{ + __asm__ __volatile__("cld; rep movsq" + : "+D"(dst), "+S"(src), "+c"(len) + : + : "memory"); +} + +/** +** Block store functions +** +** Variations: stosb(), stosw(), stosl() +** +** Description: Store a specific value into destination buffer +** +** @param dst Destination buffer +** @param val Data to copy +** @param len Byte count +*/ +static inline void stosb(void *dst, uint8_t val, uint32_t len) OPSINLINED +{ + __asm__ __volatile__("cld; rep stosb" + : "=D"(dst), "=c"(len) + : "0"(dst), "1"(len), "a"(val) + : "memory", "cc"); +} +static inline void stosw(void *dst, uint16_t val, uint32_t len) OPSINLINED +{ + __asm__ __volatile__("cld; rep stos2" + : "=D"(dst), "=c"(len) + : "0"(dst), "1"(len), "a"(val) + : "memory", "cc"); +} +static inline void stosl(void *dst, uint32_t val, uint32_t len) OPSINLINED +{ + __asm__ __volatile__("cld; rep stosl" + : "=D"(dst), "=c"(len) + : "0"(dst), "1"(len), "a"(val) + : "memory", "cc"); +} + +/**************************** +** Special register access +****************************/ + +/** +** Register read functions +** +** Variations: r_cr0(), r_cr2(), r_cr3(), r_cr4(), r_eflags(), +** r_ebp(), r_esp() +** +** Description: Reads the register indicated by its name +** +** @return Contents of the register +*/ +static inline uint32_t r_cr0(void) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__("movl %%cr0,%0" : "=r"(val)); + return val; +} +static inline uint32_t r_cr2(void) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__("movl %%cr2,%0" : "=r"(val)); + return val; +} +static inline uint32_t r_cr3(void) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__("movl %%cr3,%0" : "=r"(val)); + return val; +} +static inline uint32_t r_cr4(void) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__("movl %%cr4,%0" : "=r"(val)); + return val; +} +static inline uint32_t r_eflags(void) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__("pushfl; popl %0" : "=r"(val)); + return val; +} +static inline uint32_t r_ebp(void) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__("movl %%ebp,%0" : "=r"(val)); + return val; +} +static inline uint32_t r_esp(void) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__("movl %%esp,%0" : "=r"(val)); + return val; +} + +/** +** Register write functions +** +** Variations: w_cr0(), w_cr2(), w_cr3(), w_cr4(), w_eflags() +** +** Description: Writes a value into the CR indicated by its name +*/ +static inline void w_cr0(uint32_t val) OPSINLINED +{ + __asm__ __volatile__("movl %0,%%cr0" : : "r"(val)); +} +static inline void w_cr2(uint32_t val) OPSINLINED +{ + __asm__ __volatile__("movl %0,%%cr2" : : "r"(val)); +} +static inline void w_cr3(uint32_t val) OPSINLINED +{ + __asm__ __volatile__("movl %0,%%cr3" : : "r"(val)); +} +static inline void w_cr4(uint32_t val) OPSINLINED +{ + __asm__ __volatile__("movl %0,%%cr4" : : "r"(val)); +} +static inline void w_eflags(uint32_t eflags) OPSINLINED +{ + __asm__ __volatile__("pushl %0; popfl" : : "r"(eflags)); +} + +/** +** Descriptor table load functions +** +** Variations: w_gdt(), w_idt() +** +** Description: Load an address into the specified processor register +** +** @param addr The value to be loaded into the register +*/ +static inline void w_gdt(void *addr) OPSINLINED +{ + __asm__ __volatile__("lgdt (%0)" : : "r"(addr)); +} +static inline void w_idt(void *addr) OPSINLINED +{ + __asm__ __volatile__("lidt (%0)" : : "r"(addr)); +} + +/** +** CPU ID access +** +** Description: Retrieve CPUID information +** +** @param op Value to be placed into %eax for the operation +** @param ap Pointer to where %eax contents should be saved, or NULL +** @param bp Pointer to where %ebx contents should be saved, or NULL +** @param cp Pointer to where %ecx contents should be saved, or NULL +** @param dp Pointer to where %edx contents should be saved, or NULL +*/ +static inline void cpuid(uint32_t op, uint32_t *ap, uint32_t *bp, uint32_t *cp, + uint32_t *dp) OPSINLINED +{ + uint32_t eax, ebx, ecx, edx; + __asm__ __volatile__("cpuid" + : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) + : "a"(op)); + if (ap) + *ap = eax; + if (bp) + *bp = ebx; + if (cp) + *cp = ecx; + if (dp) + *dp = edx; +} + +/**************************** +** TLB management +****************************/ + +/** +** TLB invalidation for one page +** +** Description: Invalidate the TLB entry for an address +** +** @param addr An address within the page to be flushed +*/ +static inline void invlpg(uint32_t addr) OPSINLINED +{ + __asm__ __volatile__("invlpg (%0)" : : "r"(addr) : "memory"); +} + +/** +** TLB invalidation for all pages +** +** Description: Flush all entries from the TLB +** +** We do this by changing CR3. +*/ +static inline void flushtlb(void) OPSINLINED +{ + uint32_t cr3; + __asm__ __volatile__("movl %%cr3,%0" : "=r"(cr3)); + __asm__ __volatile__("movl %0,%%cr2" : : "r"(cr3)); +} + +/**************************** +** I/O instructions +****************************/ + +/** +** Name: inN +** +** Variations: inb(), inw(), inl() +** +** Description: Read some amount of data from the supplied I/O port +** +** @param port The i/o port to read from +** +** @return The data read from the specified port +*/ +static inline uint8_t inb(int port) OPSINLINED +{ + uint8_t data; + __asm__ __volatile__("inb %w1,%0" : "=a"(data) : "d"(port)); + return data; +} +static inline uint16_t inw(int port) OPSINLINED +{ + uint16_t data; + __asm__ __volatile__("inw %w1,%0" : "=a"(data) : "d"(port)); + return data; +} +static inline uint32_t inl(int port) OPSINLINED +{ + uint32_t data; + __asm__ __volatile__("inl %w1,%0" : "=a"(data) : "d"(port)); + return data; +} + +/** +** Name: outN +** +** Variations: outb(), outw(), outl() +** +** Description: Write some data to the specified I/O port +** +** @param port The i/o port to write to +** @param data The data to be written to the port +** +** @return The data read from the specified port +*/ +static inline void outb(int port, uint8_t data) OPSINLINED +{ + __asm__ __volatile__("outb %0,%w1" : : "a"(data), "d"(port)); +} +static inline void outw(int port, uint16_t data) OPSINLINED +{ + __asm__ __volatile__("outw %0,%w1" : : "a"(data), "d"(port)); +} +static inline void outl(int port, uint32_t data) OPSINLINED +{ + __asm__ __volatile__("outl %0,%w1" : : "a"(data), "d"(port)); +} + +/**************************** +** Miscellaneous instructions +****************************/ + +/** +** Name: breakpoint +** +** Description: Cause a breakpoint interrupt for debugging purposes +*/ +static inline void breakpoint(void) OPSINLINED +{ + __asm__ __volatile__("int3"); +} + +/** +** Name: get_ra +** +** Description: Get the return address for the calling function +** (i.e., where whoever called us will go back to) +** +** @return The address the calling routine will return to as a uint32_t +*/ +static inline uint32_t get_ra(void) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__("movl 4(%%ebp),%0" : "=r"(val)); + return val; +} + +/** +** Name: ev_wait +** +** Description: Pause until something happens +*/ +static inline void ev_wait(void) OPSINLINED +{ + __asm__ __volatile__("sti ; hlt"); +} + +/** +** Name: xchgl +** +** Description: Perform an atomic exchange with memory +** +** @param addr Memory location to be modified +** @param data Data to exchange +** +** @return The old contents of the memory location +*/ +static inline uint32_t xchgl(volatile uint32_t *addr, uint32_t data) OPSINLINED +{ + uint32_t old; + + // + indicates a read-modify-write operand + __asm__ __volatile__("lock; xchgl %0, %1" + : "+m"(*addr), "=a"(old) + : "1"(data) + : "cc"); + return old; +} + +#endif /* !ASM_SRC */ + +#endif diff --git a/kernel/old/include/x86/pic.h b/kernel/old/include/x86/pic.h new file mode 100644 index 0000000..ae3fe6c --- /dev/null +++ b/kernel/old/include/x86/pic.h @@ -0,0 +1,136 @@ +/** +** @file pic.h +** +** @author Warren R. Carithers +** @author K. Reek +** +** Definitions of constants and macros for the Intel 8259 Programmable +** Interrupt Controller. +** +*/ + +#ifndef X86PIC_H_ +#define X86PIC_H_ + +/* +** Our expected configuration is two PICs, with the secondary connected +** through the IRQ2 pin of the primary. +*/ +/* +** Port addresses for the command port and interrupt mask register port +** for both the primary and secondary PICs. +*/ +#define PIC1_CMD 0x20 // primary command +#define PIC1_DATA (PIC1_CMD + 1) // primary data / int mask register +#define PIC2_CMD 0xA0 // secondary command +#define PIC2_DATA (PIC2_CMD + 1) // secondary data / int mask register + +/* +** Initialization Command Word (ICW) definitions +** +** Initialization sequence: +** ICW1 Init command is sent to each command port. +** ICW2 vector commands are sent to the data ports. +** If "cascade mode" was selected, send ICW3 commands to the data ports. +** If "need ICW4" was selected, send ICW4 commands to the data ports. +** +** Following that sequence, the PIC is ready to accept interrupts; +** it will also accept Output Command Words (OCWs) to the data ports. +** +** PIC1_* defines are intended for the primary PIC +** PIC2_* defines are intended for the secondary PIC +** PIC_* defines are sent to both PICs +*/ +/* +** ICW1: initialization, send to command port +*/ +#define PIC_CW1_INIT 0x10 // start initialization sequence +#define PIC_CW1_NEED4 0x01 // ICW4 will also be set +#define PIC_CW1_SINGLE 0x02 // select single (vs. cascade) mode +#define PIC_CW1_INTVAL 0x04 // set call interval to 4 (vs. 8) +#define PIC_CW1_LEVEL 0x08 // use level-triggered mode (vs. edge) + +/* +** ICW2: interrupt vector base offsets, send to data port +*/ +#define PIC1_CW2_VECBASE 0x20 // IRQ0 int vector number +#define PIC2_CW2_VECBASE 0x28 // IRQ8 int vector number + +/* +** ICW3: secondary::primary attachment, send to data port +*/ +#define PIC1_CW3_SEC_IRQ2 0x04 // bit mask: secondary is on pin 2 +#define PIC2_CW3_SEC_ID 0x02 // integer: secondary id + +/* +** ICW4: operating mode, send to data port +*/ +#define PIC_CW4_PM86 0x01 // 8086 mode (vs. 8080/8085) +#define PIC_CW4_AUTOEOI 0x02 // do auto eoi's +#define PIC_CW4_UNBUF 0x00 // unbuffered mode +#define PIC_CW4_SEC_BUF 0x08 // put secondary in buffered mode +#define PIC_CW4_PRI_BUF 0x0C // put primary in buffered mode +#define PIC_CW4_SFNMODE 0x10 // "special fully nested" mode + +/* +** Operation Control Words (OCWs) +** +** After the init sequence, can send these +*/ +/* +** OCW1: interrupt mask; send to data port +*/ +#define PIC_MASK_NONE 0x00 // allow all interrupts +#define PIC_MASK_NO_IRQ0 0x01 // prevent IRQ0 interrupts +#define PIC_MASK_NO_IRQ1 0x02 // prevent IRQ1 interrupts +#define PIC_MASK_NO_IRQ2 0x04 // prevent IRQ2 interrupts +#define PIC_MASK_NO_IRQ3 0x08 // prevent IRQ3 interrupts +#define PIC_MASK_NO_IRQ4 0x10 // prevent IRQ4 interrupts +#define PIC_MASK_NO_IRQ5 0x20 // prevent IRQ5 interrupts +#define PIC_MASK_NO_IRQ6 0x40 // prevent IRQ6 interrupts +#define PIC_MASK_NO_IRQ7 0x80 // prevent IRQ7 interrupts +#define PIC_MASK_ALL 0xff // prevent all interrupts + +/* +** OCW2: EOI control, interrupt level; send to command port +*/ +#define PIC_LVL_0 0x00 // act on IRQ level 0 +#define PIC_LVL_1 0x01 // act on IRQ level 1 +#define PIC_LVL_2 0x02 // act on IRQ level 2 +#define PIC_LVL_3 0x03 // act on IRQ level 3 +#define PIC_LVL_4 0x04 // act on IRQ level 4 +#define PIC_LVL_5 0x05 // act on IRQ level 5 +#define PIC_LVL_6 0x06 // act on IRQ level 6 +#define PIC_LVL_7 0x07 // act on IRQ level 7 + +#define PIC_EOI_NON_SPEC 0x20 // non-specific EOI command +#define PIC_EOI PIC_EOI_NON_SPEC + +#define PIC_EOI_SPEC 0x60 // specific EOI command +#define PIC_SEOI PIC_EOI_SPEC +#define PIC_SEOI_LVL0 (PIC_EOI_SPEC | PIC_LVL_0) +#define PIC_SEOI_LVL1 (PIC_EOI_SPEC | PIC_LVL_1) +#define PIC_SEOI_LVL2 (PIC_EOI_SPEC | PIC_LVL_2) +#define PIC_SEOI_LVL3 (PIC_EOI_SPEC | PIC_LVL_3) +#define PIC_SEOI_LVL4 (PIC_EOI_SPEC | PIC_LVL_4) +#define PIC_SEOI_LVL5 (PIC_EOI_SPEC | PIC_LVL_5) +#define PIC_SEOI_LVL6 (PIC_EOI_SPEC | PIC_LVL_6) +#define PIC_SEOI_LVL7 (PIC_EOI_SPEC | PIC_LVL_7) + +#define PIC_EOI_ROT_NONSP 0xa0 // rotate on non-spec EOI cmd +#define PIC_EOI_SET_ROT_AUTO 0x80 // set "rotate in auto EOI mode" +#define PIC_EOI_CLR_ROT_AUTO 0x00 // clear "rotate in auto EOI mode" +#define PIC_EOI_ROT_SPEC 0xe0 // rotate on spec EOI cmd (+ level) +#define PIC_EOI_SET_PRIO 0xc0 // set priority (+ level) +#define PIC_EOI_NOP 0x40 // no operation + +/* +** OCW3: read requests, special mask mode; send to command port +*/ +#define PIC_READIRR 0x0a // read the IR register +#define PIC_READISR 0x0b // read the IS register +#define PIC_POLL 0x0c // poll +#define PIC_MASK_RESET 0x48 // reset special mask mode +#define PIC_MASK_SET 0x68 // set special mask mode + +#endif diff --git a/kernel/old/include/x86/pit.h b/kernel/old/include/x86/pit.h new file mode 100644 index 0000000..0c54539 --- /dev/null +++ b/kernel/old/include/x86/pit.h @@ -0,0 +1,81 @@ +/* +** @file pit.h +** +** @author Warren R. Carithers +** @author K. Reek +** +** Definitions of constants and macros for the +** Intel 8254 Programmable Interval Timer +** +*/ + +#ifndef X86PIT_H_ +#define X86PIT_H_ + +/* +** Hardware timer (Intel 8254 Programmable Interval Timer) +** +** Control word layout: +** +** Bit 7 6 | 5 4 | 3 2 1 | 0 +** Field SC1 SC0|RW1 RW0|M2 M1 M0 |BCD +** +** SC - select counter +** RW - read/write +** M - mode +** BCD - binary or BCD counter +*/ +/* Frequency settings */ +#define PIT_DEFAULT_TICKS_PER_SECOND 18 // actually 18.2065Hz +#define PIT_DEFAULT_MS_PER_TICK (1000 / PIT_DEFAULT_TICKS_PER_SECOND) +#define PIT_FREQ 1193182 // clock cycles/sec + +/* Port assignments */ +#define PIT_BASE_PORT 0x40 // I/O port for the timer +#define PIT_0_PORT (PIT_BASE_PORT) +#define PIT_1_PORT (PIT_BASE_PORT + 1) +#define PIT_2_PORT (PIT_BASE_PORT + 2) +#define PIT_CONTROL_PORT (PIT_BASE_PORT + 3) + +/* BCD field */ +#define PIT_USE_DECIMAL 0x00 // 16-bit binary counter (default) +#define PIT_USE_BCD 0x01 // BCD counter + +/* Timer modes */ +#define PIT_MODE_0 0x00 // int on terminal count +#define PIT_MODE_1 0x02 // one-shot +#define PIT_MODE_2 0x04 // divide-by-N +#define PIT_MODE_3 0x06 // square-wave +#define PIT_MODE_4 0x08 // software strobe +#define PIT_MODE_5 0x0a // hardware strobe + +/* Timer 0 settings */ +#define PIT_0_SELECT 0x00 // select timer 0 +#define PIT_0_LOAD 0x30 // load LSB, then MSB +#define PIT_0_NDIV PIT_MODE_2 // divide-by-N counter +#define PIT_0_SQUARE PIT_MODE_3 // square-wave mode +#define PIT_0_ENDSIGNAL 0x00 // assert OUT at end of count + +/* Timer 1 settings */ +#define PIT_1_SELECT 0x40 // select timer 1 +#define PIT_1_READ 0x30 // read/load LSB then MSB +#define PIT_1_RATE 0x06 // square-wave, for USART + +/* Timer 2 settings */ +#define PIT_2_SELECT 0x80 // select timer 1 +#define PIT_2_READ 0x30 // read/load LSB then MSB +#define PIT_2_RATE 0x06 // square-wave, for USART + +/* Timer read-back */ + +#define PIT_READBACK 0xc0 // perform a read-back +#define PIT_RB_NOT_COUNT 0x20 // don't latch the count +#define PIT_RB_NOT_STATUS 0x10 // don't latch the status +#define PIT_RB_CHAN_2 0x08 // read back channel 2 +#define PIT_RB_CHAN_1 0x04 // read back channel 1 +#define PIT_RB_CHAN_0 0x02 // read back channel 0 +#define PIT_RB_ACCESS_MASK 0x30 // access mode field +#define PIT_RB_OP_MASK 0x0e // oper mode field +#define PIT_RB_BCD_MASK 0x01 // BCD mode field + +#endif diff --git a/kernel/old/include/x86/uart.h b/kernel/old/include/x86/uart.h new file mode 100644 index 0000000..293b7b7 --- /dev/null +++ b/kernel/old/include/x86/uart.h @@ -0,0 +1,348 @@ +/* +** @file uart.h +** +** @author M. Reek +** @authors K. Reek, Warren R. Carithers +** +** Definitions for a 16540/16550 compatible UART. Definitions are taken +** from datasheets for the National Semiconductor INS8250, NS16450, and +** NS16550 UART chips, and the PC87309 Super I/O legacy peripheral chip. +** +** The naming convention is UAx_yyy_zzzzz. "x" is either 4 or 5 (see below), +** "yyy" is the name of the register to which this value applies, and +** "zzzzz" is the name of the value or field. +** +** The UA4 prefix denotes 16540 compatible functions, available in both +** chips. The UA5 prefix denotes 16550-only functions (primarily the FIFOs). +** +** For many items there are two names: one short one that matches the name +** in the chip manual, and another that is more readable. +*/ + +#ifndef UART_H +#define UART_H + +/********************************************************************* +***************************** I/O PORTS ****************************** +*********************************************************************/ + +/* +** Base port number assigned to the device +*/ +#define UA4_COM1_PORT 0x3f8 +#define UA4_COM2_PORT 0x2f8 +#define UA4_COM3_PORT 0x3e8 +#define UA4_COM4_PORT 0x2e8 + +// short name for the one we'll use +#define UA4_PORT UA4_COM1_PORT +#define UA5_PORT UA4_COM1_PORT + +/* +** Registers +** +** The 164x0 chips have the following registers. The (RO) and (WO) +** suffixes indicate read-only and write-only access. +** +** Index Register(s) +** ===== ========================================= +** 0 Receiver Data (RO), Transmitter Data (WO) +** 1 Interrupt Enable +** 2 Interrupt ID (RO), FIFO Control (WO) +** 3 Line Control, Divisor Latch +** 4 Modem Control +** 5 Line Status +** 6 Modem Status +** 7 Scratch +** +** Registers indices are relative to the base I/O port for the +** specific UART port being used (e.g., for COM1, the port addresses +** are 0x3f8 through 0x3ff). When two registers share a port and have +** different access methods (RO vs. WO), a read from the port accesses +** the RO register and a write to the port access the WO register. +** +** The Line Control and Divisor Latch registers are accessed by writing +** a byte to the port; the high-order bit determines which register is +** accessed (0 selects Line Control, 1 selects Divisor Latch), with the +** remaining bits selecting fields within the indicated register. +*/ +/* +** Receiver Data Register (read-only) +*/ +#define UA4_RXD (UA4_PORT + 0) +#define UA4_RX_DATA UA4_RXD + +/* +** Transmitter Data Register (write-only) +*/ +#define UA4_TXD (UA4_PORT + 0) +#define UA4_TX_DATA UA4_TXD + +/* +** Interrupt Enable Register +*/ +#define UA4_IER (UA4_PORT + 1) +#define UA4_INT_ENABLE_REG UA4_IER + +// fields +#define UA4_IER_RX_IE 0x01 // Rcvr High-Data-Level Int Enable +#define UA4_IER_TX_IE 0x02 // Xmitter Low-data-level Int Enable +#define UA4_IER_LS_IE 0x04 // Line Status Int Enable +#define UA4_IER_MS_IE 0x08 // Modem Status Int Enable + +// aliases +#define UA4_IER_RX_INT_ENABLE UA4_IER_RX_IE +#define UA4_IER_TX_INT_ENABLE UA4_IER_TX_IE +#define UA4_IER_LINE_STATUS_INT_ENABLE UA4_IER_LS_IE +#define UA4_IER_MODEM_STATUS_INT_ENABLE UA4_IER_MS_IE + +/* +** Interrupt Identification Register (read-only) +** +** a.k.a. Event Identification Register +*/ +#define UA4_IIR (UA4_PORT + 2) +#define UA4_EVENT_ID UA4_IIR + +// fields +#define UA4_IIR_IPF 0x01 // Interrupt Pending flag + +#define UA4_IIR_IPR_MASK 0x06 // Interrupt Priority mask +#define UA4_IIR_IPR0_MASK 0x02 // IPR bit 0 mask +#define UA4_IIR_IPR1_MASK 0x04 // IPR bit 1 mask + +#define UA5_IIR_RXFT 0x08 // RX_FIFO Timeout +#define UA5_IIR_FEN0 0x40 // FIFOs Enabled +#define UA5_IIR_FEN1 0x80 // FIFOs Enabled + +// aliases +#define UA4_IIR_INT_PENDING UA4_IIR_IPF +#define UA4_IIR_INT_PRIORITY UA4_IIR_IPR +#define UA5_IIR_RX_FIFO_TIMEOUT UA5_IIR_RXFT +#define UA5_IIR_FIFO_ENABLED_0 UA5_IIR_FEN0 +#define UA5_IIR_FIFO_ENABLED_1 UA5_IIR_FEN1 + +// IIR interrupt priorities (four-bit values) +#define UA4_IIR_INT_PRI_MASK 0x0f // Mask for extracting int priority +#define UA4_IIR_NO_INT 0x01 // no interrupt +#define UA4_IIR_LINE_STATUS 0x06 // line status interrupt +#define UA4_IIR_RX 0x04 // Receiver High Data Level +#define UA5_IIR_RX_FIFO 0x0c // Receiver FIFO timeout (16550) +#define UA4_IIR_TX 0x02 // Transmitter Low Data level +#define UA4_IIR_MODEM_STATUS 0x00 // Modem Status + +// aliases +#define UA4_IIR_NO_INT_PENDING UA4_IIR_NO_INT +#define UA4_IIR_LINE_STATUS_INT_PENDING UA4_IIR_LINE_STATUS +#define UA4_IIR_RX_INT_PENDING UA4_IIR_RX +#define UA5_IIR_RX_FIFO_TIMEOUT_INT_PENDING UA5_IIR_RX_FIFO +#define UA4_IIR_TX_INT_PENDING UA4_IIR_TX +#define UA4_IIR_MODEM_STATUS_INT_PENDING UA4_IIR_MODEM_STATUS + +/* +** FIFO Control Register (16550 only, write-only) +*/ +#define UA5_FCR (UA5_PORT + 2) +#define UA5_FIFO_CTL UA5_FCR + +#define UA5_FCR_FIFO_RESET 0x00 // Reset the FIFO +#define UA5_FCR_FIFO_EN 0x01 // FIFO Enable +#define UA5_FCR_RXSR 0x02 // Receiver Soft Reset +#define UA5_FCR_TXSR 0x04 // Transmitter Soft Reset + +#define UA5_FCR_TXFT_MASK 0x30 // TX_FIFO threshold level mask +#define UA5_FCR_TXFT0_MASK 0x10 // TXFT bit 0 mask +#define UA5_FCR_TXFT1_MASK 0x20 // TXFT bit 1 mask +#define UA5_FCR_TX_FIFO_1 0x00 // 1 char +#define UA5_FCR_TX_FIFO_3 0x10 // 3 char +#define UA5_FCR_TX_FIFO_9 0x20 // 9 char +#define UA5_FCR_TX_FIFO_13 0x30 // 13 char + +#define UA5_FCR_RXFT_MASK 0xc0 // RX_FIFO threshold level mask +#define UA5_FCR_RXFT0_MASK 0x40 // RXFT bit 0 mask +#define UA5_FCR_RXFT1_MASK 0x80 // RXFT bit 1 mask +#define UA5_FCR_RX_FIFO_1 0x00 // 1 char +#define UA5_FCR_RX_FIFO_4 0x40 // 4 char +#define UA5_FCR_RX_FIFO_8 0x80 // 8 char +#define UA5_FCR_RX_FIFO_14 0xc0 // 14 char + +// aliases +#define UA5_FCR_FIFO_ENABLED UA5_FCR_FIFO_EN +#define UA5_FCR_RX_SOFT_RESET UA5_FCR_RXSR +#define UA5_FCR_TX_SOFT_RESET UA5_FCR_TXSR +#define UA5_FCR_TX_FIFO_1_CHAR UA5_FCR_TX_FIFO_1 +#define UA5_FCR_TX_FIFO_3_CHAR UA5_FCR_TX_FIFO_3 +#define UA5_FCR_TX_FIFO_9_CHAR UA5_FCR_TX_FIFO_9 +#define UA5_FCR_TX_FIFO_13_CHAR UA5_FCR_TX_FIFO_13 +#define UA5_FCR_RX_FIFO_1_CHAR UA5_FCR_RX_FIFO_1 +#define UA5_FCR_RX_FIFO_4_CHAR UA5_FCR_RX_FIFO_4 +#define UA5_FCR_RX_FIFO_8_CHAR UA5_FCR_RX_FIFO_8 +#define UA5_FCR_RX_FIFO_14_CHAR UA5_FCR_RX_FIFO_14 + +/* +** Line Control Register (available in all banks) +** +** Selected when bit 7 of the value written to the port is a 0. +*/ +#define UA4_LCR (UA4_PORT + 3) +#define UA4_LINE_CTL UA4_LCR + +#define UA4_LCR_WLS_MASK 0x03 // Word Length Select mask +#define UA4_LCR_WLS0_MASK 0x01 // WLS bit 0 mask +#define UA4_LCR_WLS1_MASK 0x02 // WLS bit 1 mask +#define UA4_LCR_WLS_5 0x00 // 5 bits per char +#define UA4_LCR_WLS_6 0x01 // 6 bits per char +#define UA4_LCR_WLS_7 0x02 // 7 bits per char +#define UA4_LCR_WLS_8 0x03 // 8 bits per char + +#define UA4_LCR_STB 0x04 // Stop Bits +#define UA4_LCR_1_STOP_BIT 0x00 +#define UA4_LCR_2_STOP_BIT 0x04 + +#define UA4_LCR_PEN 0x08 // Parity Enable +#define UA4_LCR_EPS 0x10 // Even Parity Select +#define UA4_LCR_STKP 0x20 // Sticky Parity +#define UA4_LCR_NO_PARITY 0x00 +#define UA4_LCR_ODD_PARITY UA4_LCR_PEN +#define UA4_LCR_EVEN_PARITY (UA4_LCR_PEN | UA4_LCR_EPS) +#define UA4_LCR_PARITY_LOGIC_1 (UA4_LCR_PEN | UA4_LCR_STKP) +#define UA4_LCR_PARITY_LOGIC_0 (UA4_LCR_PEN | UA4_LCR_EPS | UA4_LCR_STKP) + +#define UA4_LCR_SBRK 0x40 // Set Break +#define UA4_LCR_DLAB 0x80 // Divisor Latch select bit + +// aliases +#define UA4_LCR_STOP_BITS UA4_LCR_STB +#define UA4_LCR_PARITY_ENABLE UA4_LCR_PEN +#define UA4_LCR_SET_BREAK UA4_LCR_SBRK +#define UA4_LCR_BANK_SELECT_ENABLE UA4_LCR_BKSE + +/* +** Divisor Latch Registers +** Divisor Latch Least Significant (DLL) +** Divisor Latch Most Significant (DLM) +** +** These contain the lower and upper halves of the 16-bit divisor for +** baud rate generation. +** +** Accessing them requires sending a command to LCR with the most +** significant bit (0x80, the DLAB field) set. This "unlocks" the +** Divisor Latch registers, which are accessed at UA4_PORT+0 and +** UA4_PORT+1 (i.e., in place of the RXD/TXD and IE registers). To +** "re-lock" the Divisor Latch registers, write a command byte to +** LCR with 0 in the DLAB bit. +*/ +#define UA4_DLL (UA4_PORT + 0) // Divisor Latch (least sig.) +#define UA4_DLM (UA4_PORT + 1) // Divisor Latch (most sig.) + +// aliases +#define UA4_DIVISOR_LATCH_LS UA4_DLL +#define UA4_DIVISOR_LATCH_MS UA4_DLM + +// Baud rate divisor high and low bytes +#define BAUD_HIGH_BYTE(x) (((x) >> 8) & 0xff) +#define BAUD_LOW_BYTE(x) ((x) & 0xff) + +// Baud rate divisors +#define DL_BAUD_50 2304 +#define DL_BAUD_75 1536 +#define DL_BAUD_110 1047 +#define DL_BAUD_150 768 +#define DL_BAUD_300 384 +#define DL_BAUD_600 192 +#define DL_BAUD_1200 96 +#define DL_BAUD_1800 64 +#define DL_BAUD_2000 58 +#define DL_BAUD_2400 48 +#define DL_BAUD_3600 32 +#define DL_BAUD_4800 24 +#define DL_BAUD_7200 16 +#define DL_BAUD_9600 12 +#define DL_BAUD_14400 8 +#define DL_BAUD_19200 6 +#define DL_BAUD_28800 4 +#define DL_BAUD_38400 3 +#define DL_BAUD_57600 2 +#define DL_BAUD_115200 1 + +/* +** Modem Control Register +*/ +#define UA4_MCR (UA4_PORT + 4) +#define UA4_MODEM_CTL UA4_MCR + +#define UA4_MCR_DTR 0x01 // Data Terminal Ready +#define UA4_MCR_RTS 0x02 // Ready to Send +#define UA4_MCR_RILP 0x04 // Loopback Interrupt Request +#define UA4_MCR_ISEN 0x08 // Interrupt Signal Enable +#define UA4_MCR_DCDLP 0x08 // DCD Loopback +#define UA4_MCR_LOOP 0x10 // Loopback Enable + +// aliases +#define UA4_MCR_DATA_TERMINAL_READY UA4_MCR_DTR +#define UA4_MCR_READY_TO_SEND UA4_MCR_RTS +#define UA4_MCR_LOOPBACK_INT_REQ UA4_MCR_RILP +#define UA4_MCR_INT_SIGNAL_ENABLE UA4_MCR_ISEN +#define UA4_MCR_LOOPBACK_DCD UA4_MCR_DCDLP +#define UA4_MCR_LOOPBACK_ENABLE UA4_MCR_LOOP + +/* +** Line Status Register +*/ +#define UA4_LSR (UA4_PORT + 5) +#define UA4_LINE_STATUS UA4_LSR + +#define UA4_LSR_RXDA 0x01 // Receiver Data Available +#define UA4_LSR_OE 0x02 // Overrun Error +#define UA4_LSR_PE 0x04 // Parity Error +#define UA4_LSR_FE 0x08 // Framing Error +#define UA4_LSR_BRK 0x10 // Break Event Detected +#define UA4_LSR_TXRDY 0x20 // Transmitter Ready +#define UA4_LSR_TXEMP 0x40 // Transmitter Empty +#define UA4_LSR_ER_INF 0x80 // Error in RX_FIFO + +// aliases +#define UA4_LSR_RX_DATA_AVAILABLE UA4_LSR_RXDA +#define UA4_LSR_OVERRUN_ERROR UA4_LSR_OE +#define UA4_LSR_PARITY_ERROR UA4_LSR_PE +#define UA4_LSR_FRAMING_ERROR UA4_LSR_FE +#define UA4_LSR_BREAK_DETECTED UA4_LSR_BRK +#define UA4_LSR_TX_READY UA4_LSR_TXRDY +#define UA4_LSR_TX_EMPTY UA4_LSR_TXEMP +#define UA4_LSR_RX_FIFO_ERROR UA4_LSR_ER_INF + +/* +** Modem Status Register +*/ +#define UA4_MSR (UA4_PORT + 6) +#define UA4_MODEM_STATUS UA4_MSR + +#define UA4_MSR_DCTS 0x01 // Delta Clear to Send +#define UA4_MSR_DDSR 0x02 // Delta Data Set Ready +#define UA4_MSR_TERI 0x04 // Trailing Edge Ring Indicate +#define UA4_MSR_DDCD 0x08 // Delta Data Carrier Detect +#define UA4_MSR_CTS 0x10 // Clear to Send +#define UA4_MSR_DSR 0x20 // Data Set Ready +#define UA4_MSR_RI 0x40 // Ring Indicate +#define UA4_MSR_DCD 0x80 // Data Carrier Detect + +// aliases +#define UA4_MSR_DELTA_CLEAR_TO_SEND UA4_MSR_DCTS +#define UA4_MSR_DELTA_DATA_SET_READY UA4_MSR_DDSR +#define UA4_MSR_TRAILING_EDGE_RING UA4_MSR_TERI +#define UA4_MSR_DELTA_DATA_CARRIER_DETECT UA4_MSR_DDCD +#define UA4_MSR_CLEAR_TO_SEND UA4_MSR_CTS +#define UA4_MSR_DATA_SET_READY UA4_MSR_DSR +#define UA4_MSR_RING_INDICATE UA4_MSR_RI +#define UA4_MSR_DATA_CARRIER_DETECT UA4_MSR_DCD + +/* +** Scratch Register +** +** Not used by the UART; usable as a "scratchpad" register for +** temporary storage. +*/ +#define UA4_SCR (UA4_PORT + 7) +#define UA4_SCRATCH UA4_UA5_SCR + +#endif /* uart.h */ diff --git a/kernel/isrs.S b/kernel/old/isrs.S index f5fdbca..f5fdbca 100644 --- a/kernel/isrs.S +++ b/kernel/old/isrs.S diff --git a/kernel/old/kernel.c b/kernel/old/kernel.c new file mode 100644 index 0000000..ce2e9dd --- /dev/null +++ b/kernel/old/kernel.c @@ -0,0 +1,400 @@ +/** +** @file kernel.c +** +** @author CSCI-452 class of 20245 +** +** @brief Kernel support routines +*/ + +#define KERNEL_SRC + +#include <common.h> +#include <cio.h> +#include <clock.h> +#include <kmem.h> +#include <procs.h> +#include <sio.h> +#include <syscalls.h> +#include <user.h> +#include <userids.h> +#include <vm.h> + +/* +** PRIVATE DEFINITIONS +*/ + +/* +** PRIVATE DATA TYPES +*/ + +/* +** PRIVATE GLOBAL VARIABLES +*/ + +/* +** PUBLIC GLOBAL VARIABLES +*/ + +// character buffers, usable throughout the OS +// nto guaranteed to retain their contents across an exception return +char b256[256]; // primarily used for message creation +char b512[512]; // used by PANIC macro + +/* +** PRIVATE FUNCTIONS +*/ + +/* +** PRIVATE FUNCTIONS +*/ + +/** +** report - report the system configuration +** +** Prints configuration information about the OS on the console monitor. +** +** @param dtrace Decode the TRACE options +*/ +static void kreport(bool_t dtrace) +{ + cio_puts("\n-------------------------------\n"); + cio_printf("Config: N_PROCS = %d", N_PROCS); + cio_printf(" N_PRIOS = %d", N_PRIOS); + cio_printf(" N_STATES = %d", N_STATES); + cio_printf(" CLOCK = %dHz\n", CLOCK_FREQ); + + // This code is ugly, but it's the simplest way to + // print out the values of compile-time options + // without spending a lot of execution time at it. + + cio_puts("Options: " +#ifdef RPT_INT_UNEXP + " R-uint" +#endif +#ifdef RPT_INT_MYSTERY + " R-mint" +#endif +#ifdef TRACE_CX + " CX" +#endif +#ifdef CONSOLE_STATS + " Cstats" +#endif + ); // end of cio_puts() call + +#ifdef SANITY + cio_printf(" SANITY = %d", SANITY); +#endif +#ifdef STATUS + cio_printf(" STATUS = %d", STATUS); +#endif + +#if TRACE > 0 + cio_printf(" TRACE = 0x%04x\n", TRACE); + + // decode the trace settings if that was requested + if (TRACING_SOMETHING && dtrace) { + // this one is simpler - we rely on string literal + // concatenation in the C compiler to create one + // long string to print out + + cio_puts("Tracing:" +#if TRACING_PCB + " PCB" +#endif +#if TRACING_VM + " VM" +#endif +#if TRACING_QUEUE + " QUE" +#endif +#if TRACING_SCHED + " SCHED" +#endif +#if TRACING_DISPATCH + " DISPATCH" +#endif +#if TRACING_SYSCALLS + " SCALL" +#endif +#if TRACING_SYSRETS + " SRET" +#endif +#if TRACING_EXIT + " EXIT" +#endif +#if TRACING_INIT + " INIT" +#endif +#if TRACING_KMEM + " KM" +#endif +#if TRACING_KMEM_FREELIST + " KMFL" +#endif +#if TRACING_KMEM_INIT + " KMIN" +#endif +#if TRACING_FORK + " FORK" +#endif +#if TRACING_EXEC + " EXEC" +#endif +#if TRACING_SIO_STAT + " S_STAT" +#endif +#if TRACING_SIO_ISR + " S_ISR" +#endif +#if TRACING_SIO_RD + " S_RD" +#endif +#if TRACING_SIO_WR + " S_WR" +#endif +#if TRACING_USER + " USER" +#endif +#if TRACING_ELF + " ELF" +#endif + ); // end of cio_puts() call + } +#endif /* TRACE > 0 */ + + cio_putchar('\n'); +} + +#if defined(CONSOLE_STATS) +/** +** stats - callback routine for console statistics +** +** Called by the CIO module when a key is pressed on the +** console keyboard. Depending on the key, it will print +** statistics on the console display, or will cause the +** user shell process to be dispatched. +** +** This code runs as part of the CIO ISR. +*/ +static void stats(int code) +{ + switch (code) { + case 'a': // dump the active table + ptable_dump("\nActive processes", false); + break; + + case 'c': // dump context info for all active PCBs + ctx_dump_all("\nContext dump"); + break; + + case 'p': // dump the active table and all PCBs + ptable_dump("\nActive processes", true); + break; + + case 'q': // dump the queues + // code to dump out any/all queues + pcb_queue_dump("R", ready, true); + pcb_queue_dump("W", waiting, true); + pcb_queue_dump("S", sleeping, true); + pcb_queue_dump("Z", zombie, true); + pcb_queue_dump("I", sioread, true); + break; + + case 'r': // print system configuration information + report(true); + break; + + // ignore CR and LF + case '\r': // FALL THROUGH + case '\n': + break; + + default: + cio_printf("console: unknown request '0x%02x'\n", code); + // FALL THROUGH + + case 'h': // help message + cio_puts("\nCommands:\n" + " a -- dump the active table\n" + " c -- dump contexts for active processes\n" + " h -- this message\n" + " p -- dump the active table and all PCBs\n" + " q -- dump the queues\n" + " r -- print system configuration\n"); + break; + } +} +#endif + +/* +** PUBLIC FUNCTIONS +*/ + +/** +** main - system initialization routine +** +** Called by the startup code immediately before returning into the +** first user process. +** +** Making this type 'int' keeps the compiler happy. +*/ +int main(void) +{ + /* + ** BOILERPLATE CODE - taken from basic framework + ** + ** Initialize interrupt stuff. + */ + + init_interrupts(); // IDT and PIC initialization + + /* + ** Console I/O system. + ** + ** Does not depend on the other kernel modules, so we can + ** initialize it before we initialize the kernel memory + ** and queue modules. + */ + +#if defined(CONSOLE_STATS) + cio_init(stats); +#else + cio_init(NULL); // no console callback routine +#endif + + cio_clearscreen(); // wipe out whatever is there + + /* + ** TERM-SPECIFIC CODE STARTS HERE + */ + + /* + ** Initialize various OS modules + ** + ** Other modules (clock, SIO, syscall, etc.) are expected to + ** install their own ISRs in their initialization routines. + */ + + cio_puts("System initialization starting.\n"); + cio_puts("-------------------------------\n"); + + cio_puts("Modules:"); + + // call the module initialization functions, being + // careful to follow any module precedence requirements + + km_init(); // MUST BE FIRST +#if TRACING_KMEM || TRACING_KMEM_FREE + delay(DELAY_2_SEC); // approximately +#endif + + // other module initialization calls here + clk_init(); // clock + pcb_init(); // process (PCBs, queues, scheduler) +#if TRACING_PCB + delay(DELAY_2_SEC); +#endif + sio_init(); // serial i/o + sys_init(); // system call +#if TRACING_SYSCALLS || TRACING_SYSRETS + delay(DELAY_2_SEC); +#endif + vm_init(); // virtual memory + user_init(); // user code handling + + cio_puts("\nModule initialization complete.\n"); + + // report our configuration options + kreport(true); + cio_puts("-------------------------------\n"); + + delay(DELAY_2_SEC); + + /* + ** Other tasks typically performed here: + ** + ** Enabling any I/O devices (e.g., SIO xmit/rcv) + */ + + /* + ** Create the initial user process + ** + ** This code is largely stolen from the fork() and exec() + ** implementations in syscalls.c; if those change, this must + ** also change. + */ + + // if we can't get a PCB, there's no use continuing! + assert(pcb_alloc(&init_pcb) == SUCCESS); + + // fill in the necessary details + init_pcb->pid = PID_INIT; + init_pcb->state = STATE_NEW; + init_pcb->priority = PRIO_HIGH; + + // find the 'init' program + prog_t *prog = user_locate(Init); + assert(prog != NULL); + + // command-line arguments for 'init' + const char *args[2] = { "init", NULL }; + + // load it + assert(user_load(prog, init_pcb, args, true) == SUCCESS); + + // send it on its merry way + schedule(init_pcb); + dispatch(); + +#ifdef TRACE_CX + // if we're using a scrolling region, wait a bit more and then set it up + delay(DELAY_7_SEC); + + // define a scrolling region in the top 7 lines of the screen + cio_setscroll(0, 7, 99, 99); + + // clear it + cio_clearscroll(); + + // clear the top line + cio_puts_at( + 0, 0, + "* "); + // separator + cio_puts_at( + 0, 6, + "================================================================================"); +#endif + + /* + ** END OF TERM-SPECIFIC CODE + ** + ** Finally, report that we're all done. + */ + + cio_puts("System initialization complete.\n"); + cio_puts("-------------------------------\n"); + + sio_enable(SIO_RX); + +#if 0 + // produce a "system state" report + cio_puts( "System status: Queues " ); + pcb_queue_dump( "R", ready, true ); + pcb_queue_dump( "W", waiting, true ); + pcb_queue_dump( "S", sleeping, true ); + pcb_queue_dump( "Z", zombie, true ); + pcb_queue_dump( "I", sioread, true ); + ptable_dump_counts(); + pcb_dump( "Current: ", current, true ); + + delay( DELAY_3_SEC ); + + vm_print( current->pdir, true, TwoLevel ); + + delay( DELAY_3_SEC ); +#endif + + return 0; +} diff --git a/kernel/kmem.c b/kernel/old/kmem.c index fe0c7de..fe0c7de 100644 --- a/kernel/kmem.c +++ b/kernel/old/kmem.c diff --git a/kernel/list.c b/kernel/old/list.c index 5492615..5492615 100644 --- a/kernel/list.c +++ b/kernel/old/list.c diff --git a/kernel/procs.c b/kernel/old/procs.c index 82c4c98..82c4c98 100644 --- a/kernel/procs.c +++ b/kernel/old/procs.c diff --git a/kernel/support.c b/kernel/old/support.c index 89834ee..89834ee 100644 --- a/kernel/support.c +++ b/kernel/old/support.c diff --git a/kernel/syscalls.c b/kernel/old/syscalls.c index 92a0a23..92a0a23 100644 --- a/kernel/syscalls.c +++ b/kernel/old/syscalls.c diff --git a/kernel/user.c b/kernel/old/user.c index 5759534..5759534 100644 --- a/kernel/user.c +++ b/kernel/old/user.c diff --git a/kernel/vm.c b/kernel/old/vm.c index 814ff12..814ff12 100644 --- a/kernel/vm.c +++ b/kernel/old/vm.c diff --git a/kernel/vmtables.c b/kernel/old/vmtables.c index 113fd8b..113fd8b 100644 --- a/kernel/vmtables.c +++ b/kernel/old/vmtables.c diff --git a/kernel/startup.S b/kernel/startup.S deleted file mode 100644 index 94b93b0..0000000 --- a/kernel/startup.S +++ /dev/null @@ -1,161 +0,0 @@ -/* -** @file startup.S -** -** @author Jon Coles -** @authors Warren R. Carithers, K. Reek -** -** SP startup code. -** -** This code prepares the various registers for execution of -** the program. It sets up all the segment registers and the -** runtime stack. By the time this code is running, we're in -** protected mode already. -*/ - -#define KERNEL_SRC -#define ASM_SRC - -# .arch i386 - -#include <common.h> -#include <bootstrap.h> -#include <x86/arch.h> -#include <x86/bios.h> -#include <vm.h> - -/* -** Configuration options - define in Makefile -** -** CLEAR_BSS include code to clear all BSS space -** OS_CONFIG OS-related (vs. just standalone) variations -*/ - -/* -** A symbol for locating the beginning of the code. -*/ - .text - - .globl begtext - .globl _start -_start = V2PNC(begtext) - -/* -** The entry point. When we get here, we have just entered protected -** mode, so all the segment registers are incorrect except for CS. -*/ -begtext: - - cli /* seems to be reset on entry to p. mode */ - movb $NMI_ENABLE, %al /* re-enable NMIs (bootstrap */ - outb $CMOS_ADDR /* turned them off) */ - -/* -** Set the data and stack segment registers (code segment register -** was set by the long jump that switched us into protected mode). -*/ - xorl %eax, %eax /* clear EAX */ - movw $GDT_DATA, %ax /* GDT entry #3 - data segment */ - movw %ax, %ds /* for all four data segment registers */ - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - - movw $GDT_STACK, %ax /* entry #4 is the stack segment */ - movw %ax, %ss - - movl $TARGET_STACK, %esp /* set up the system stack pointer */ - -#ifdef CLEAR_BSS -/* -** Zero the BSS segment -** -** These symbols are defined automatically by the linker, but they're -** defined at their virtual addresses rather than their physical addresses, -** and we haven't enabled paging yet. -*/ - .globl __bss_start, _end - - movl $V2PNC(__bss_start), %edi -clearbss: - movl $0, (%edi) - addl $4, %edi - cmpl $V2PNC(_end), %edi - jb clearbss -#endif /* CLEAR_BSS */ - -/* -** Enable paging. We use "large" pages for the initial page directory -** so that a one-level hierarchy will work for us. Once we have set -** up our memory freelist, we'll create a two-level hierarchy using -** "normal" 4KB pages. -*/ - # enable large pages - movl %cr4, %eax - orl $(CR4_PSE), %eax - movl %eax, %cr4 - - # set the page directory - .globl firstpdir - movl $(V2PNC(firstpdir)), %eax - movl %eax, %cr3 - - # turn on paging - movl %cr0, %eax - orl $(CR0_PG), %eax - movl %eax, %cr0 - - # reset our stack pointer - movl $(kstack + SZ_KSTACK), %esp - - # set the initial frame pointer - xorl %ebp, %ebp - - # now, jump and switch into using high addresses - # we use an indirect jump here because the assembler - # would ordinarily generate a PC-relative target - # address for the jump, which would not have the - # desired effect - movl $onward, %eax - jmp *%eax - -onward: - -/* -** Call the system initialization routine. -** -** Alternate idea: push the address of isr_restore -** and just do an indirect jump? -*/ - .globl main - - movl $main, %eax - call *%eax - -/* -** At this point, main() must have created the first user -** process, and we're ready to shift into user mode. The user -** stack for that process must have the initial context in it; -** we treat this as a "return from interrupt" event, and just -** transfer to the code that restores the user context. -*/ - - .globl isr_restore - jmp isr_restore - - .data - -/* -** Define the kernel stack here, at a multiple-of-16 address -*/ - .p2align 4 - .globl kstack -kstack: .space SZ_KSTACK, 0 - -/* -** Define the initial kernel ESP here, as well. It should point -** to the first byte after the stack. -*/ - - .globl kernel_esp -kernel_esp: - .long kstack + SZ_KSTACK diff --git a/ulib/entry.S b/ulib/entry.S new file mode 100644 index 0000000..87ad9c7 --- /dev/null +++ b/ulib/entry.S @@ -0,0 +1,25 @@ +// +// user-level startup routine +// + .text + .globl _start + .globl main + .globl exit + +// entry point - this is where the kernel starts us running +_start: + // we immediately call main() + call main + + // if we come back from that, it means the user + // program didn't call exit(), in which case the + // value returned from main() is the exit status + + // push that value onto the stack and call exit() + subl $12, %esp + pushl %eax + call exit + + // if we come back from that, something bad has + // happened, so we just lock up +1: jmp 1b diff --git a/ulib/spawn.c b/ulib/spawn.c new file mode 100644 index 0000000..78b1a53 --- /dev/null +++ b/ulib/spawn.c @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <error.h> +#include <unistd.h> + +int wait(int32_t *status) +{ + return (waitpid(0, status)); +} + +int spawn(uint_t prog, char **args) +{ + int32_t pid; + + pid = fork(); + if (pid != 0) { + // failure, or we are the parent + return (pid); + } + + // we are the child + pid = getpid(); + + // child inherits parent's priority level + + exec(prog, args); + + // uh-oh.... + + fprintf(stderr, "Child %d exec() #%u failed\n", pid, prog); + + exit(EXIT_FAILURE); +} diff --git a/ulib/syscall.S b/ulib/syscall.S new file mode 100644 index 0000000..46fcb89 --- /dev/null +++ b/ulib/syscall.S @@ -0,0 +1,93 @@ +/** +** @file ulibs.S +** +** @author CSCI-452 class of 20245 +** +** @brief assembly-language user-level library functions +*/ + +#define ASM_SRC + +// get the system call codes + +#include <syscalls.h> + +/** +** System call stubs +** +** All have the same structure: +** +** move a code into EAX +** generate the interrupt +** return to the caller +** +** As these are simple "leaf" routines, we don't use +** the standard enter/leave method to set up a stack +** frame - that takes time, and we don't really need it. +** +** Could be modified to use the UNIX/Linux convention of +** having the syscall code set the 'C' flag to indicate that +** the value being returned in %EAX is an error code: +** +** ... +** int $VEC_SYSCALL +** jc set_errno +** ret +** ... +** +** .globl errno +** set_errno: +** movl %eax, errno +** movl $-1, %eax +** ret +*/ + +#define SYSCALL(name) \ + .globl name ; \ +name: ; \ + movl $SYS_##name, %eax ; \ + int $VEC_SYSCALL ; \ + ret + +/* +** "real" system calls +*/ + +SYSCALL(exit) +SYSCALL(waitpid) +SYSCALL(fork) +SYSCALL(exec) +SYSCALL(read) +SYSCALL(write) +SYSCALL(getpid) +SYSCALL(getppid) +SYSCALL(gettime) +SYSCALL(getprio) +SYSCALL(setprio) +SYSCALL(kill) +SYSCALL(sleep) + +/* +** This is a bogus system call; it's here so that we can test +** our handling of out-of-range syscall codes in the syscall ISR. +*/ +SYSCALL(bogus) + +/* +** Other library functions +*/ + +/** +** fake_exit() +** +** Dummy "startup" function +** +** calls exit(%eax) - serves as the "return to" code for +** main() functions, in case they don't call exit() themselves +*/ + + .globl fake_exit +fake_exit: + // alternate: could push a "fake exit" status + pushl %eax // termination status returned by main() + call exit // terminate this process |