mirror of
https://github.com/kenshineto/kern.git
synced 2025-04-10 20:47:25 +00:00
move old kernel code (for now) into kernel/old, trying to get long mode
This commit is contained in:
parent
ec3c37d1d4
commit
a524eb3846
51 changed files with 5132 additions and 847 deletions
Makefilebuild.zigcompile_flags.txt
kernel
entry.S
include/comus
kernel.ckernel.ldold
cio.c
startup.Sdrivers
include
bindings.hbootstrap.hcio.hclock.hcompat.hdebug.hdefs.hkdefs.hklib.hkmem.hlist.hparams.hprocs.hserial.hsio.hsupport.hsyscalls.htypes.huser.hvm.hvmtables.h
isrs.Skernel.ckmem.clist.cprocs.csupport.csyscalls.cuser.cvm.cvmtables.cx86
ulib
6
Makefile
6
Makefile
|
@ -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
|
||||
|
||||
|
|
213
build.zig
213
build.zig
|
@ -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, .{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
-c
|
||||
-std=c99
|
||||
-Iinclude
|
||||
-Ikernel/include
|
||||
-ffreestanding
|
||||
-fno-builtin
|
||||
-Wall
|
||||
|
|
158
kernel/entry.S
Normal file
158
kernel/entry.S
Normal file
|
@ -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
|
||||
|
1
kernel/include/comus/memory.h
Normal file
1
kernel/include/comus/memory.h
Normal file
|
@ -0,0 +1 @@
|
|||
#include <memory/mapping.h>
|
20
kernel/include/comus/memory/mapping.h
Normal file
20
kernel/include/comus/memory/mapping.h
Normal file
|
@ -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
|
399
kernel/kernel.c
399
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) ;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
/**
|
||||
** @file clock.c
|
||||
**
|
||||
** @author CSCI-452 class of 20245
|
||||
**
|
||||
** @brief Clock module implementation
|
||||
*/
|
||||
|
||||
#define KERNEL_SRC
|
||||
|
||||
#include <common.h>
|
|
@ -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
|
73
kernel/old/include/bindings.h
Normal file
73
kernel/old/include/bindings.h
Normal file
|
@ -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 */
|
119
kernel/old/include/bootstrap.h
Normal file
119
kernel/old/include/bootstrap.h
Normal file
|
@ -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
|
287
kernel/old/include/cio.h
Normal file
287
kernel/old/include/cio.h
Normal file
|
@ -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
|
55
kernel/old/include/clock.h
Normal file
55
kernel/old/include/clock.h
Normal file
|
@ -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
|
132
kernel/old/include/compat.h
Normal file
132
kernel/old/include/compat.h
Normal file
|
@ -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
|
356
kernel/old/include/debug.h
Normal file
356
kernel/old/include/debug.h
Normal file
|
@ -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
|
130
kernel/old/include/defs.h
Normal file
130
kernel/old/include/defs.h
Normal file
|
@ -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
|
157
kernel/old/include/kdefs.h
Normal file
157
kernel/old/include/kdefs.h
Normal file
|
@ -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
|
57
kernel/old/include/klib.h
Normal file
57
kernel/old/include/klib.h
Normal file
|
@ -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
|
138
kernel/old/include/kmem.h
Normal file
138
kernel/old/include/kmem.h
Normal file
|
@ -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
|
68
kernel/old/include/list.h
Normal file
68
kernel/old/include/list.h
Normal file
|
@ -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
|
33
kernel/old/include/params.h
Normal file
33
kernel/old/include/params.h
Normal file
|
@ -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
|
457
kernel/old/include/procs.h
Normal file
457
kernel/old/include/procs.h
Normal file
|
@ -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
|
3
kernel/old/include/serial.h
Normal file
3
kernel/old/include/serial.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
168
kernel/old/include/sio.h
Normal file
168
kernel/old/include/sio.h
Normal file
|
@ -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
|
86
kernel/old/include/support.h
Normal file
86
kernel/old/include/support.h
Normal file
|
@ -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
|
80
kernel/old/include/syscalls.h
Normal file
80
kernel/old/include/syscalls.h
Normal file
|
@ -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
|
13
kernel/old/include/types.h
Normal file
13
kernel/old/include/types.h
Normal file
|
@ -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
|
139
kernel/old/include/user.h
Normal file
139
kernel/old/include/user.h
Normal file
|
@ -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
|
501
kernel/old/include/vm.h
Normal file
501
kernel/old/include/vm.h
Normal file
|
@ -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
|
43
kernel/old/include/vmtables.h
Normal file
43
kernel/old/include/vmtables.h
Normal file
|
@ -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
|
299
kernel/old/include/x86/arch.h
Normal file
299
kernel/old/include/x86/arch.h
Normal file
|
@ -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
|
395
kernel/old/include/x86/ops.h
Normal file
395
kernel/old/include/x86/ops.h
Normal file
|
@ -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
|
136
kernel/old/include/x86/pic.h
Normal file
136
kernel/old/include/x86/pic.h
Normal file
|
@ -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
|
81
kernel/old/include/x86/pit.h
Normal file
81
kernel/old/include/x86/pit.h
Normal file
|
@ -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
|
348
kernel/old/include/x86/uart.h
Normal file
348
kernel/old/include/x86/uart.h
Normal file
|
@ -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 */
|
400
kernel/old/kernel.c
Normal file
400
kernel/old/kernel.c
Normal file
|
@ -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;
|
||||
}
|
161
kernel/startup.S
161
kernel/startup.S
|
@ -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
|
25
ulib/entry.S
Normal file
25
ulib/entry.S
Normal file
|
@ -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
|
32
ulib/spawn.c
Normal file
32
ulib/spawn.c
Normal file
|
@ -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);
|
||||
}
|
93
ulib/syscall.S
Normal file
93
ulib/syscall.S
Normal file
|
@ -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
|
Loading…
Add table
Reference in a new issue