Initial Spring 2016 commit.

This commit is contained in:
Geoffrey Challen
2015-12-23 00:50:04 +00:00
commit cafa9f5690
732 changed files with 92195 additions and 0 deletions

17
kern/Makefile Normal file
View File

@@ -0,0 +1,17 @@
#
# Toplevel makefile for the OS/161 kernel tree.
#
# Note: actual kernels are not compiled here; they are compiled in
# compile/FOO where FOO is a kernel configuration name.
#
# We don't actually do anything from here except install includes.
#
TOP=..
.include "$(TOP)/mk/os161.config.mk"
INCLUDES=\
include/kern include/kern \
arch/$(MACHINE)/include/kern include/kern/$(MACHINE)
.include "$(TOP)/mk/os161.includes.mk"

View File

@@ -0,0 +1,79 @@
#
# The machine dependent sources for MIPS.
#
# Standard C functions
machine mips file ../common/libc/arch/mips/setjmp.S
# 64-bit integer ops support for gcc
machine mips file ../common/gcc-millicode/adddi3.c
machine mips file ../common/gcc-millicode/anddi3.c
machine mips file ../common/gcc-millicode/ashldi3.c
machine mips file ../common/gcc-millicode/ashrdi3.c
machine mips file ../common/gcc-millicode/cmpdi2.c
machine mips file ../common/gcc-millicode/divdi3.c
machine mips file ../common/gcc-millicode/iordi3.c
machine mips file ../common/gcc-millicode/lshldi3.c
machine mips file ../common/gcc-millicode/lshrdi3.c
machine mips file ../common/gcc-millicode/moddi3.c
machine mips file ../common/gcc-millicode/muldi3.c
machine mips file ../common/gcc-millicode/negdi2.c
machine mips file ../common/gcc-millicode/notdi2.c
machine mips file ../common/gcc-millicode/qdivrem.c
machine mips file ../common/gcc-millicode/subdi3.c
machine mips file ../common/gcc-millicode/ucmpdi2.c
machine mips file ../common/gcc-millicode/udivdi3.c
machine mips file ../common/gcc-millicode/umoddi3.c
machine mips file ../common/gcc-millicode/xordi3.c
#
# Low-level stuff ("locore")
# The platform should select cache handling and exception handling from
# among these:
#
# cache-mips1.S
# cache-mips161.S
# cache-mips32.S
#
# exception-mips1.S
# exception-mips32.S
#
machine mips file arch/mips/locore/trap.c # Common trap handler.
#
# Thread subsystem
#
machine mips file arch/mips/thread/cpu.c # CPU control.
machine mips file arch/mips/thread/switch.S # Thread context switch
machine mips file arch/mips/thread/switchframe.c # New thread prep
machine mips file arch/mips/thread/thread_machdep.c # MD thread code
machine mips file arch/mips/thread/threadstart.S # New thread startup
#
# VM system
# The platform should select TLB handling from among these:
#
# tlb-mips1.S
# tlb-mips161.S
# tlb-mips32.S
#
machine mips file arch/mips/vm/ram.c # Physical memory accounting
# This is included here rather than in conf.kern because
# it may not be suitable for all architectures.
machine mips file vm/copyinout.c # copyin/out et al.
# For the early assignments, we supply a very stupid MIPS-only skeleton
# of a VM system. It is just barely capable of running a single userlevel
# program as long as that program's not very large.
defoption dumbvm
machine mips optfile dumbvm arch/mips/vm/dumbvm.c
#
# System call layer
#
machine mips file arch/mips/syscall/syscall.c # System call handler

View File

@@ -0,0 +1,98 @@
/*
* This is a pile of crap that tells the linker how to link the kernel,
* because it's too stupid to be able to work it out on its own.
*/
ENTRY(__start)
_DYNAMIC_LINK = 0;
SECTIONS
{
/*
* Base address for the kernel.
*/
. = 0x80000200;
/*
* Read-only loaded sections.
*/
/* code */
.text : { *(.text) }
/* linker-provided symbol for end of code */
_etext = .;
/* read-only data */
.rodata : { *(.rodata) *(.rodata.*) }
/* MIPS register-usage blather */
.reginfo : { *(.reginfo) }
/*
* Move to a fresh page. This method puts read-only and
* read-write material on separate pages without having to
* waste space on page-alignment in the on-disk file; the
* on-disk page that contains both text and data is mapped
* twice.
*
* For mips kernels we can't write-protect the text anyhow so
* there's no point doing it.
*/
/* . = . + 0x1000; */
/*
* Read-write loaded sections.
*/
/* initialized data */
.data : {
*(.data)
CONSTRUCTORS
}
/* Value for GP register */
_gp = ALIGN(16) + 0x7ff0;
/* Small data accessed via GP register */
.lit8 : { *(.lit8) }
.lit4 : { *(.lit4) }
.sdata : { *(.sdata) }
/* cleared-to-zero data */
.sbss : { *(.sbss *.scommon) }
.bss : { *(.bss) *(COMMON) }
/* linker-provided symbol for end of program */
_end = .;
/*
* Debug info
*/
/* stabs debug sections */
.stab 0: { *(.stab) }
.stabstr 0: { *(.stabstr) }
/* DWARF debug sections */
.debug 0: { *(.debug) }
.line 0: { *(.line) }
.debug_srcinfo 0: { *(.debug_srcinfo) }
.debug_sfnames 0: { *(.debug_sfnames) }
.debug_aranges 0: { *(.debug_aranges) }
.debug_pubnames 0: { *(.debug_pubnames) }
.debug_info 0: { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0: { *(.debug_abbrev) }
.debug_line 0: { *(.debug_line) }
.debug_frame 0: { *(.debug_frame) }
.debug_str 0: { *(.debug_str) }
.debug_loc 0: { *(.debug_loc) }
.debug_macinfo 0: { *(.debug_macinfo) }
.debug_weaknames 0: { *(.debug_weaknames) }
.debug_funcnames 0: { *(.debug_funcnames) }
.debug_typenames 0: { *(.debug_typenames) }
.debug_varnames 0: { *(.debug_varnames) }
/* These must appear regardless of . */
.gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
.gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _MIPS_CURRENT_H_
#define _MIPS_CURRENT_H_
/*
* Macro for current thread, or current cpu.
*
* This file should only be included via <current.h> (q.v.)
*
* On mips we track the current thread. There's an architectural
* issue that informs this choice: there's no easy way to find the
* current cpu, the current thread, or even the kernel stack of the
* current thread when entering the kernel at trap time. (On most CPUs
* there's a canonical way to find at least the stack.)
*
* Therefore we do the following:
*
* - We misuse a kernel-settable field of a nonessential MMU register
* to hold the CPU number.
*
* - On trap entry we use this number to index an array that gets us
* both the kernel stack and curthread.
*
* - We tell the compiler not to use the s7 register and keep
* curthread there.
*
* Note that if you want to change this scheme to use a different
* register, or change to a different scheme, you need to touch three
* places: here, the mips-specific kernel CFLAGS in the makefiles, and
* the trap entry and return code.
*/
#ifdef __GNUC__
register struct thread *curthread __asm("$23"); /* s7 register */
#else
#error "Don't know how to declare curthread in this compiler"
#endif
#undef __NEED_CURTHREAD
#define __NEED_CURCPU
/* For how we've defined it, curthread gets set first, then curcpu. */
#define INIT_CURCPU(cpu, thread) (curthread = (thread), curcpu = (cpu))
#endif /* _MIPS_CURRENT_H_ */

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _MIPS_ELF_H_
#define _MIPS_ELF_H_
/*
* MIPS machine-dependent definitions for the ELF binary format.
*/
/* The ELF executable type. */
#define EM_MACHINE EM_MIPS
/* Linker relocation codes. SIZE DESCRIPTION */
#define R_MIPS_NONE 0 /* --- nop */
#define R_MIPS_16 1 /* u16 value */
#define R_MIPS_32 2 /* u32 value */
#define R_MIPS_REL32 3 /* u32 value relative to patched address */
#define R_MIPS_26 4 /* u26 j/jal instruction address field */
#define R_MIPS_HI16 5 /* u16 %hi(sym) as below */
#define R_MIPS_LO16 6 /* s16 %lo(sym) as below */
#define R_MIPS_GPREL16 7 /* s16 offset from GP register */
#define R_MIPS_LITERAL 8 /* s16 GPREL16 for file-local symbols (?) */
#define R_MIPS_GOT16 9 /* u16 offset into global offset table */
#define R_MIPS_PC16 10 /* s16 PC-relative reference */
#define R_MIPS_CALL16 11 /* u16 call through global offset table */
#define R_MIPS_GPREL32 12 /* s32 offset from GP register */
/* %hi/%lo are defined so %hi(sym) << 16 + %lo(sym) = sym */
#endif /* _MIPS_ELF_H_ */

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _KERN_MIPS_ENDIAN_H_
#define _KERN_MIPS_ENDIAN_H_
/*
* Endianness. While the MIPS can be either big-endian (mipseb) or
* little-endian (mipsel), at least for now we only do mipseb.
*
* This file should only be included via <kern/endian.h> which in turn
* should be gotten via <endian.h> in the kernel or <arpa/inet.h> in
* userland.
*/
#define _BYTE_ORDER _BIG_ENDIAN
#endif /* _KERN_MIPS_ENDIAN_H_ */

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Macros for general-purpose register numbers for MIPS.
*
* Exported to userlevel because it's ~standard for that architecture.
*/
#ifndef _KERN_MIPS_REGDEFS_H_
#define _KERN_MIPS_REGDEFS_H_
#define z0 $0 /* always zero register */
#define AT $1 /* assembler temp register */
#define v0 $2 /* value 0 */
#define v1 $3 /* value 1 */
#define a0 $4 /* argument 0 */
#define a1 $5 /* argument 1 */
#define a2 $6 /* argument 2 */
#define a3 $7 /* argument 3 */
#define t0 $8 /* temporary (caller-save) 0 */
#define t1 $9 /* temporary (caller-save) 1 */
#define t2 $10 /* temporary (caller-save) 2 */
#define t3 $11 /* temporary (caller-save) 3 */
#define t4 $12 /* temporary (caller-save) 4 */
#define t5 $13 /* temporary (caller-save) 5 */
#define t6 $14 /* temporary (caller-save) 6 */
#define t7 $15 /* temporary (caller-save) 7 */
#define s0 $16 /* saved (callee-save) 0 */
#define s1 $17 /* saved (callee-save) 1 */
#define s2 $18 /* saved (callee-save) 2 */
#define s3 $19 /* saved (callee-save) 3 */
#define s4 $20 /* saved (callee-save) 4 */
#define s5 $21 /* saved (callee-save) 5 */
#define s6 $22 /* saved (callee-save) 6 */
#define s7 $23 /* saved (callee-save) 7 */
#define t8 $24 /* temporary (caller-save) 8 */
#define t9 $25 /* temporary (caller-save) 9 */
#define k0 $26 /* kernel temporary 0 */
#define k1 $27 /* kernel temporary 1 */
#define gp $28 /* global pointer */
#define sp $29 /* stack pointer */
#define s8 $30 /* saved (callee-save) 8 = frame pointer */
#define ra $31 /* return address */
#endif /* _KERN_MIPS_REGDEFS_H_ */

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _MIPS_SETJMP_H_
#define _MIPS_SETJMP_H_
/*
* MIPS jmp_buf definition.
*/
/*
* Must save: s0-s8, sp, ra (11 registers)
* Don't change __JB_REGS without adjusting mips_setjmp.S accordingly.
*/
#define __JB_REGS 11
/* A jmp_buf is an array of __JB_REGS registers */
typedef uint32_t jmp_buf[__JB_REGS];
#endif /* _MIPS_SETJMP_H_ */

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _KERN_MIPS_SIGNAL_H_
#define _KERN_MIPS_SIGNAL_H_
/*
* Structure used to hold the register values for returning from a
* userland signal handler - basically the saved register values from
* whatever userlevel execution context the signal interrupted. Fill
* this in as needed, if you ever implement signal handlers. (Which you
* probably won't.)
*/
struct sigcontext {
/* Dummy. */
};
#endif /* _KERN_MIPS_SIGNAL_H_ */

View File

@@ -0,0 +1,78 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _KERN_MIPS_TYPES_H_
#define _KERN_MIPS_TYPES_H_
/*
* Machine-dependent types visible to userland.
* (Kernel-only types should go in mips/types.h.)
* 32-bit MIPS version.
*
* See kern/types.h for an explanation of the underscores.
*/
/* Sized integer types, with convenient short names */
typedef char __i8; /* 8-bit signed integer */
typedef short __i16; /* 16-bit signed integer */
typedef int __i32; /* 32-bit signed integer */
typedef long long __i64; /* 64-bit signed integer */
typedef unsigned char __u8; /* 8-bit unsigned integer */
typedef unsigned short __u16; /* 16-bit unsigned integer */
typedef unsigned int __u32; /* 32-bit unsigned integer */
typedef unsigned long long __u64; /* 64-bit unsigned integer */
/* Further standard C types */
typedef long __intptr_t; /* Signed pointer-sized integer */
typedef unsigned long __uintptr_t; /* Unsigned pointer-sized integer */
/*
* Since we're a 32-bit platform, size_t, ssize_t, and ptrdiff_t can
* correctly be either (unsigned) int or (unsigned) long. However, if we
* don't define it to the same one gcc is using, gcc will get
* upset. If you switch compilers and see otherwise unexplicable type
* errors involving size_t, try changing this.
*/
#if 1
typedef unsigned __size_t; /* Size of a memory region */
typedef int __ssize_t; /* Signed type of same size */
typedef int __ptrdiff_t; /* Difference of two pointers */
#else
typedef unsigned long __size_t; /* Size of a memory region */
typedef long __ssize_t; /* Signed type of same size */
typedef long __ptrdiff_t; /* Difference of two pointers */
#endif
/* Number of bits per byte. */
#define __CHAR_BIT 8
#endif /* _KERN_MIPS_TYPES_H_ */

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2013
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _MIPS_MEMBAR_H_
#define _MIPS_MEMBAR_H_
/*
* On the mips there's only one memory barrier instruction, so these
* are all the same. This is not true on many other CPUs (x86, arm,
* sparc, powerpc, etc.) We also mark the instruction as a compiler-
* level barrier by telling gcc that it destroys memory; this prevents
* gcc from reordering loads and stores around it.
*
* See include/membar.h for further information.
*/
MEMBAR_INLINE
void
membar_any_any(void)
{
__asm volatile(
".set push;" /* save assembler mode */
".set mips32;" /* allow MIPS32 instructions */
"sync;" /* do it */
".set pop" /* restore assembler mode */
: /* no outputs */
: /* no inputs */
: "memory"); /* "changes" memory */
}
MEMBAR_INLINE void membar_load_load(void) { membar_any_any(); }
MEMBAR_INLINE void membar_store_store(void) { membar_any_any(); }
MEMBAR_INLINE void membar_store_any(void) { membar_any_any(); }
MEMBAR_INLINE void membar_any_store(void) { membar_any_any(); }
#endif /* _MIPS_MEMBAR_H_ */

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _MIPS_SPECIALREG_H_
#define _MIPS_SPECIALREG_H_
/*
* Coprocessor 0 (system processor) register numbers
*/
#define c0_index $0 /* TLB entry index register */
#define c0_random $1 /* TLB random slot register */
#define c0_entrylo $2 /* TLB entry contents (low-order half) */
/* c0_entrylo0 $2 */ /* MIPS-II and up only */
/* c0_entrylo1 $3 */ /* MIPS-II and up only */
#define c0_context $4 /* some precomputed pagetable stuff */
/* c0_pagemask $5 */ /* MIPS-II and up only */
/* c0_wired $6 */ /* MIPS-II and up only */
#define c0_vaddr $8 /* virtual addr of failing memory access */
#define c0_count $9 /* cycle counter (MIPS-II and up) */
#define c0_entryhi $10 /* TLB entry contents (high-order half) */
#define c0_compare $11 /* on-chip timer control (MIPS-II and up) */
#define c0_status $12 /* processor status register */
#define c0_cause $13 /* exception cause register */
#define c0_epc $14 /* exception PC register */
#define c0_prid $15 /* processor ID register */
/* c0_config $16 */ /* MIPS-II and up only */
/* c0_lladdr $17 */ /* MIPS-II and up only */
/* c0_watchlo $18 */ /* MIPS-II and up only */
/* c0_watchhi $19 */ /* MIPS-II and up only */
/*
* Mode bits in c0_status
*/
#define CST_IEc 0x00000001 /* current: interrupt enable */
#define CST_KUc 0x00000002 /* current: user mode */
#define CST_IEp 0x00000004 /* previous: interrupt enable */
#define CST_KUp 0x00000008 /* previous: user mode */
#define CST_IEo 0x00000010 /* old: interrupt enable */
#define CST_KUo 0x00000020 /* old: user mode */
#define CST_MODEMASK 0x0000003f /* mask for the above */
#define CST_IRQMASK 0x0000ff00 /* mask for the individual irq enable bits */
#define CST_BEV 0x00400000 /* bootstrap exception vectors flag */
/*
* Fields of the c0_cause register
*/
#define CCA_UTLB 0x00000001 /* true if UTLB exception (set by our asm) */
#define CCA_CODE 0x0000003c /* EX_foo in trapframe.h */
#define CCA_IRQS 0x0000ff00 /* Currently pending interrupts */
#define CCA_COPN 0x30000000 /* Coprocessor number for EX_CPU */
#define CCA_JD 0x80000000 /* True if exception happened in jump delay */
#define CCA_CODESHIFT 2 /* shift for CCA_CODE field */
/*
* Fields of the c0_index register
*/
#define CIN_P 0x80000000 /* nonzero -> TLB probe found nothing */
#define CIN_INDEX 0x00003f00 /* 6-bit index into TLB */
#define CIN_INDEXSHIFT 8 /* shift for CIN_INDEX field */
/*
* Fields of the c0_context register
*
* The intent of c0_context is that you can manage virtually-mapped
* page tables in kseg2; then you load the base address of the current
* page table into c0_context. On a TLB miss the failing address is
* masked and shifted and appears in the VSHIFT field, and c0_context
* thereby contains the address of the page table entry you need to
* load into the TLB. This can be used to make TLB refill very fast.
*
* However, in OS/161 we use CTX_PTBASE to hold the current CPU
* number. This (or something like it) is fairly important to have and
* there's no other good place in the chip to put it. See discussions
* elsewhere.
*/
#define CTX_VSHIFT 0x001ffffc /* shifted/masked copy of c0_vaddr */
#define CTX_PTBASE 0xffe00000 /* page table base address */
#define CTX_PTBASESHIFT 21 /* shift for CTX_PBASE field */
/*
* Hardwired exception handler addresses.
*/
#define EXADDR_UTLB 0x80000000
#define EXADDR_GENERAL 0x80000080
#endif /* _MIPS_SPECIALREG_H_ */

View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _MIPS_SPINLOCK_H_
#define _MIPS_SPINLOCK_H_
#include <cdefs.h>
/* Type of value needed to actually spin on */
typedef unsigned spinlock_data_t;
/* Initializer for use by SPINLOCK_INITIALIZER */
#define SPINLOCK_DATA_INITIALIZER 0
/* Atomic operations on spinlock_data_t */
SPINLOCK_INLINE
void spinlock_data_set(volatile spinlock_data_t *sd, unsigned val);
SPINLOCK_INLINE
spinlock_data_t spinlock_data_get(volatile spinlock_data_t *sd);
SPINLOCK_INLINE
spinlock_data_t spinlock_data_testandset(volatile spinlock_data_t *sd);
////////////////////////////////////////////////////////////
/*
* Assign a spinlock_data_t. On mips assigment of a plain 32-bit value
* is one instruction, and instructions are atomic with respect to
* memory.
*/
SPINLOCK_INLINE
void
spinlock_data_set(volatile spinlock_data_t *sd, unsigned val)
{
*sd = val;
}
/*
* Read a spinlock_data_t. On mips reading a plain 32-bit value is one
* instruction, and instructions are atomic with respect to memory.
*/
SPINLOCK_INLINE
spinlock_data_t
spinlock_data_get(volatile spinlock_data_t *sd)
{
return *sd;
}
/*
* Test-and-set a spinlock_data_t. Use the LL/SC instructions to
* make it atomic.
*
* LL (load linked) loads a machine word from memory, and marks the
* address. SC (store conditional) stores a machine word to memory,
* but succeeds only if the address is marked from a previous LL on
* the same processor. Stores from other processors clear that mark,
* as do traps on the current processor. Note that there may be no
* other memory accesses (besides instruction fetches) between the LL
* and the SC or the behavior is *undefined*. You can only use LL/SC
* to atomically update one machine word.
*/
SPINLOCK_INLINE
spinlock_data_t
spinlock_data_testandset(volatile spinlock_data_t *sd)
{
spinlock_data_t x;
spinlock_data_t y;
/*
* Test-and-set using LL/SC.
*
* Load the existing value into X, and use Y to store 1.
* After the SC, Y contains 1 if the store succeeded,
* 0 if it failed.
*
* On failure, return 1 to pretend that the spinlock
* was already held.
*/
y = 1;
__asm volatile(
".set push;" /* save assembler mode */
".set mips32;" /* allow MIPS32 instructions */
".set volatile;" /* avoid unwanted optimization */
"ll %0, 0(%2);" /* x = *sd */
"sc %1, 0(%2);" /* *sd = y; y = success? */
".set pop" /* restore assembler mode */
: "=&r" (x), "+r" (y) : "r" (sd));
if (y == 0) {
return 1;
}
return x;
}
#endif /* _MIPS_SPINLOCK_H_ */

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _MIPS_THREAD_H_
#define _MIPS_THREAD_H_
/*
* Machine-dependent thread bits.
*/
#include <setjmp.h>
typedef void (*badfaultfunc_t)(void);
struct thread_machdep {
badfaultfunc_t tm_badfaultfunc; /* fault hook used by copyin/out */
jmp_buf tm_copyjmp; /* longjmp area used by copyin/out */
};
#endif /* _MIPS_THREAD_H_ */

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _MIPS_TLB_H_
#define _MIPS_TLB_H_
/*
* MIPS-specific TLB access functions.
*
* tlb_random: write the TLB entry specified by ENTRYHI and ENTRYLO
* into a "random" TLB slot chosen by the processor.
*
* IMPORTANT NOTE: never write more than one TLB entry with the
* same virtual page field.
*
* tlb_write: same as tlb_random, but you choose the slot.
*
* tlb_read: read a TLB entry out of the TLB into ENTRYHI and ENTRYLO.
* INDEX specifies which one to get.
*
* tlb_probe: look for an entry matching the virtual page in ENTRYHI.
* Returns the index, or a negative number if no matching entry
* was found. ENTRYLO is not actually used, but must be set; 0
* should be passed.
*
* IMPORTANT NOTE: An entry may be matching even if the valid bit
* is not set. To completely invalidate the TLB, load it with
* translations for addresses in one of the unmapped address
* ranges - these will never be matched.
*/
void tlb_random(uint32_t entryhi, uint32_t entrylo);
void tlb_write(uint32_t entryhi, uint32_t entrylo, uint32_t index);
void tlb_read(uint32_t *entryhi, uint32_t *entrylo, uint32_t index);
int tlb_probe(uint32_t entryhi, uint32_t entrylo);
/*
* TLB entry fields.
*
* Note that the MIPS has support for a 6-bit address space ID. In the
* interests of simplicity, we don't use it. The fields related to it
* (TLBLO_GLOBAL and TLBHI_PID) can be left always zero, as can the
* bits that aren't assigned a meaning.
*
* The TLBLO_DIRTY bit is actually a write privilege bit - it is not
* ever set by the processor. If you set it, writes are permitted. If
* you don't set it, you'll get a "TLB Modify" exception when a write
* is attempted.
*
* There is probably no reason in the course of CS161 to use TLBLO_NOCACHE.
*/
/* Fields in the high-order word */
#define TLBHI_VPAGE 0xfffff000
/* TLBHI_PID 0x00000fc0 */
/* Fields in the low-order word */
#define TLBLO_PPAGE 0xfffff000
#define TLBLO_NOCACHE 0x00000800
#define TLBLO_DIRTY 0x00000400
#define TLBLO_VALID 0x00000200
/* TLBLO_GLOBAL 0x00000100 */
/*
* Values for completely invalid TLB entries. The TLB entry index should
* be passed to TLBHI_INVALID; this prevents loading the same invalid
* entry into multiple TLB slots.
*/
#define TLBHI_INVALID(entryno) ((0x80000+(entryno))<<12)
#define TLBLO_INVALID() (0)
/*
* Number of TLB entries in the processor.
*/
#define NUM_TLB 64
#endif /* _MIPS_TLB_H_ */

View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _MIPS_TRAPFRAME_H_
#define _MIPS_TRAPFRAME_H_
/*
* Structure describing what is saved on the stack during entry to
* the exception handler.
*
* This must agree with the code in exception-*.S.
*/
struct trapframe {
uint32_t tf_vaddr; /* coprocessor 0 vaddr register */
uint32_t tf_status; /* coprocessor 0 status register */
uint32_t tf_cause; /* coprocessor 0 cause register */
uint32_t tf_lo;
uint32_t tf_hi;
uint32_t tf_ra; /* Saved register 31 */
uint32_t tf_at; /* Saved register 1 (AT) */
uint32_t tf_v0; /* Saved register 2 (v0) */
uint32_t tf_v1; /* etc. */
uint32_t tf_a0;
uint32_t tf_a1;
uint32_t tf_a2;
uint32_t tf_a3;
uint32_t tf_t0;
uint32_t tf_t1;
uint32_t tf_t2;
uint32_t tf_t3;
uint32_t tf_t4;
uint32_t tf_t5;
uint32_t tf_t6;
uint32_t tf_t7;
uint32_t tf_s0;
uint32_t tf_s1;
uint32_t tf_s2;
uint32_t tf_s3;
uint32_t tf_s4;
uint32_t tf_s5;
uint32_t tf_s6;
uint32_t tf_s7;
uint32_t tf_t8;
uint32_t tf_t9;
uint32_t tf_k0; /* dummy (see exception-mips1.S comments) */
uint32_t tf_k1; /* dummy */
uint32_t tf_gp;
uint32_t tf_sp;
uint32_t tf_s8;
uint32_t tf_epc; /* coprocessor 0 epc register */
};
/*
* MIPS exception codes.
*/
#define EX_IRQ 0 /* Interrupt */
#define EX_MOD 1 /* TLB Modify (write to read-only page) */
#define EX_TLBL 2 /* TLB miss on load */
#define EX_TLBS 3 /* TLB miss on store */
#define EX_ADEL 4 /* Address error on load */
#define EX_ADES 5 /* Address error on store */
#define EX_IBE 6 /* Bus error on instruction fetch */
#define EX_DBE 7 /* Bus error on data load *or* store */
#define EX_SYS 8 /* Syscall */
#define EX_BP 9 /* Breakpoint */
#define EX_RI 10 /* Reserved (illegal) instruction */
#define EX_CPU 11 /* Coprocessor unusable */
#define EX_OVF 12 /* Arithmetic overflow */
/*
* Function to enter user mode. Does not return. The trapframe must
* be on the thread's own stack or bad things will happen.
*/
__DEAD void mips_usermode(struct trapframe *tf);
/*
* Arrays used to load the kernel stack and curthread on trap entry.
*/
extern vaddr_t cpustacks[];
extern vaddr_t cputhreads[];
#endif /* _MIPS_TRAPFRAME_H_ */

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _MIPS_TYPES_H_
#define _MIPS_TYPES_H_
/*
* Machine-dependent types that are *not* made visible to userland.
* Those that are made visible are found in kern/machine/types.h.
* 32-bit MIPS version.
*
* (Use the underscore versions of the base type names because this
* file is included by types.h before the non-underscore versions are
* defined.)
*/
typedef __u32 paddr_t;
typedef __u32 vaddr_t;
#endif /* _MIPS_TYPES_H_ */

129
kern/arch/mips/include/vm.h Normal file
View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _MIPS_VM_H_
#define _MIPS_VM_H_
/*
* Machine-dependent VM system definitions.
*/
#define PAGE_SIZE 4096 /* size of VM page */
#define PAGE_FRAME 0xfffff000 /* mask for getting page number from addr */
/*
* MIPS-I hardwired memory layout:
* 0xc0000000 - 0xffffffff kseg2 (kernel, tlb-mapped)
* 0xa0000000 - 0xbfffffff kseg1 (kernel, unmapped, uncached)
* 0x80000000 - 0x9fffffff kseg0 (kernel, unmapped, cached)
* 0x00000000 - 0x7fffffff kuseg (user, tlb-mapped)
*
* (mips32 is a little different)
*/
#define MIPS_KUSEG 0x00000000
#define MIPS_KSEG0 0x80000000
#define MIPS_KSEG1 0xa0000000
#define MIPS_KSEG2 0xc0000000
/*
* The first 512 megs of physical space can be addressed in both kseg0 and
* kseg1. We use kseg0 for the kernel. This macro returns the kernel virtual
* address of a given physical address within that range. (We assume we're
* not using systems with more physical space than that anyway.)
*
* N.B. If you, say, call a function that returns a paddr or 0 on error,
* check the paddr for being 0 *before* you use this macro. While paddr 0
* is not legal for memory allocation or memory management (it holds
* exception handler code) when converted to a vaddr it's *not* NULL, *is*
* a valid address, and will make a *huge* mess if you scribble on it.
*/
#define PADDR_TO_KVADDR(paddr) ((paddr)+MIPS_KSEG0)
/*
* The top of user space. (Actually, the address immediately above the
* last valid user address.)
*/
#define USERSPACETOP MIPS_KSEG0
/*
* The starting value for the stack pointer at user level. Because
* the stack is subtract-then-store, this can start as the next
* address after the stack area.
*
* We put the stack at the very top of user virtual memory because it
* grows downwards.
*/
#define USERSTACK USERSPACETOP
/*
* Interface to the low-level module that looks after the amount of
* physical memory we have.
*
* ram_getsize returns one past the highest valid physical
* address. (This value is page-aligned.) The extant RAM ranges from
* physical address 0 up to but not including this address.
*
* ram_getfirstfree returns the lowest valid physical address. (It is
* also page-aligned.) Memory at this address and above is available
* for use during operation, and excludes the space the kernel is
* loaded into and memory that is grabbed in the very early stages of
* bootup. Memory below this address is already in use and should be
* reserved or otherwise not managed by the VM system. It should be
* called exactly once when the VM system initializes to take over
* management of physical memory.
*
* ram_stealmem can be used before ram_getsize is called to allocate
* memory that cannot be freed later. This is intended for use early
* in bootup before VM initialization is complete.
*/
void ram_bootstrap(void);
paddr_t ram_stealmem(unsigned long npages);
paddr_t ram_getsize(void);
paddr_t ram_getfirstfree(void);
/*
* TLB shootdown bits.
*
* We'll take up to 16 invalidations before just flushing the whole TLB.
*/
struct tlbshootdown {
/*
* Change this to what you need for your VM design.
*/
int ts_placeholder;
};
#define TLBSHOOTDOWN_MAX 16
#endif /* _MIPS_VM_H_ */

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2001, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <kern/mips/regdefs.h>
/*
* Cache flushing code for the System/161 MIPS variant, which
* (for now at least) has magically coherent caches. Almost all
* real MIPS processors require explicit cache control of one
* form or another; it can be quite a nuisance. (It is particularly
* nasty on the MIPS-1, that is, r2000/r3000.)
*/
.text
.set noreorder
.globl mips_flushicache
.type mips_flushicache,@function
.ent mips_flushicache
mips_flushicache:
j ra
nop
.end mips_flushicache

View File

@@ -0,0 +1,355 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <kern/mips/regdefs.h>
#include <mips/specialreg.h>
/*
* Entry points for exceptions.
*
* MIPS-1 (r2000/r3000) style exception handling, with the "rfe"
* instruction rather than "eret", and the three sets of status bits.
*/
/*
* Do not allow the assembler to use $1 (at), because we need to be
* able to save it.
*/
.set noat
.set noreorder
/*
* UTLB exception handler.
*
* This code is copied to address 0x80000000, where the MIPS processor
* automatically invokes it.
*
* To avoid colliding with the other exception code, it must not
* exceed 128 bytes (32 instructions).
*
* This is the special entry point for the fast-path TLB refill for
* faults in the user address space. We don't implement fast-path TLB
* refill by default. Note that if you do, you either need to make
* sure the refill code doesn't fault or write extra code in
* common_exception to tidy up after such faults.
*/
.text
.globl mips_utlb_handler
.type mips_utlb_handler,@function
.ent mips_utlb_handler
mips_utlb_handler:
j common_exception /* Don't need to do anything special */
nop /* Delay slot */
.globl mips_utlb_end
mips_utlb_end:
.end mips_utlb_handler
/*
* General exception handler.
*
* This code is copied to address 0x80000080, where
* the MIPS processor automatically invokes it.
*/
.text
.globl mips_general_handler
.type mips_general_handler,@function
.ent mips_general_handler
mips_general_handler:
j common_exception /* Don't need to do anything special */
nop /* Delay slot */
.globl mips_general_end
mips_general_end:
.end mips_general_handler
/* This keeps gdb from conflating common_exception and mips_general_end */
nop /* padding */
/*
* Shared exception code for both handlers.
*/
.text
.type common_exception,@function
.ent common_exception
common_exception:
mfc0 k0, c0_status /* Get status register */
andi k0, k0, CST_KUp /* Check the we-were-in-user-mode bit */
beq k0, $0, 1f /* If clear, from kernel, already have stack */
nop /* delay slot */
/* Coming from user mode - find kernel stack */
mfc0 k1, c0_context /* we keep the CPU number here */
srl k1, k1, CTX_PTBASESHIFT /* shift it to get just the CPU number */
sll k1, k1, 2 /* shift it back to make an array index */
lui k0, %hi(cpustacks) /* get base address of cpustacks[] */
addu k0, k0, k1 /* index it */
move k1, sp /* Save previous stack pointer in k1 */
b 2f /* Skip to common code */
lw sp, %lo(cpustacks)(k0) /* Load kernel stack pointer (in delay slot) */
1:
/* Coming from kernel mode - just save previous stuff */
move k1, sp /* Save previous stack in k1 (delay slot) */
2:
/*
* At this point:
* Interrupts are off. (The processor did this for us.)
* k0 contains the value for curthread, to go into s7.
* k1 contains the old stack pointer.
* sp points into the kernel stack.
* All other registers are untouched.
*/
/*
* Allocate stack space for 37 words to hold the trap frame,
* plus four more words for a minimal argument block, plus
* one more for proper (64-bit) stack alignment.
*/
addi sp, sp, -168
/*
* Save general registers.
* We exclude k0/k1, which the kernel is free to clobber (and which
* we already have clobbered), and $0, whose value is fixed.
*
* The order here must match mips/include/trapframe.h.
*
* gdb disassembles this code to try to figure out what registers
* are where, and it isn't very bright. So in order to make gdb be
* able to trace the stack back through here, we play some silly
* games.
*
* In particular:
* (1) We store the return address register into the epc slot,
* which makes gdb think it's the return address slot. Then
* we store the real epc value over that.
* (2) We store the current sp into the sp slot, which makes gdb
* think it's the stack pointer slot. Then we store the real
* value.
* (3) gdb also assumes that saved registers in a function are
* saved in order. This is why we put epc where it is, and
* handle the real value of ra afterwards.
* (4) Because gdb will think we're saving k0 and k1, we need to
* leave slots for them in the trap frame, even though the
* stuff we save there is useless.
*
* This logic has not been tested against a recent gdb and has
* probably bitrotted. Someone(TM) should figure out what gdb
* currently expects -- or maybe even patch gdb to understand a
* better form of this that doesn't waste so many cycles.
*/
sw ra, 160(sp) /* dummy for gdb */
sw s8, 156(sp) /* save s8 */
sw sp, 152(sp) /* dummy for gdb */
sw gp, 148(sp) /* save gp */
sw k1, 144(sp) /* dummy for gdb */
sw k0, 140(sp) /* dummy for gdb */
sw k1, 152(sp) /* real saved sp */
nop /* delay slot for store */
mfc0 k1, c0_epc /* Copr.0 reg 13 == PC for exception */
sw k1, 160(sp) /* real saved PC */
sw t9, 136(sp)
sw t8, 132(sp)
sw s7, 128(sp)
sw s6, 124(sp)
sw s5, 120(sp)
sw s4, 116(sp)
sw s3, 112(sp)
sw s2, 108(sp)
sw s1, 104(sp)
sw s0, 100(sp)
sw t7, 96(sp)
sw t6, 92(sp)
sw t5, 88(sp)
sw t4, 84(sp)
sw t3, 80(sp)
sw t2, 76(sp)
sw t1, 72(sp)
sw t0, 68(sp)
sw a3, 64(sp)
sw a2, 60(sp)
sw a1, 56(sp)
sw a0, 52(sp)
sw v1, 48(sp)
sw v0, 44(sp)
sw AT, 40(sp)
sw ra, 36(sp)
/*
* Save special registers.
*/
mfhi t0
mflo t1
sw t0, 32(sp)
sw t1, 28(sp)
/*
* Save remaining exception context information.
*/
mfc0 t2, c0_status /* Copr.0 reg 11 == status */
sw t2, 20(sp)
mfc0 t3, c0_vaddr /* Copr.0 reg 8 == faulting vaddr */
sw t3, 16(sp)
mfc0 t4, c0_cause
sw t4, 24(sp) /* Copr.0 reg 13 == exception cause */
/*
* Pretend to save $0 for gdb's benefit.
*/
sw $0, 12(sp)
/*
* Load the curthread register if coming from user mode.
*/
andi k0, t2, CST_KUp /* Check the we-were-in-user-mode bit */
beq k0, $0, 3f /* If clear, were in kernel, skip ahead */
nop /* delay slot */
mfc0 k1, c0_context /* we keep the CPU number here */
srl k1, k1, CTX_PTBASESHIFT /* shift it to get just the CPU number */
sll k1, k1, 2 /* shift it back to make an array index */
lui k0, %hi(cputhreads) /* get base address of cputhreads[] */
addu k0, k0, k1 /* index it */
lw s7, %lo(cputhreads)(k0) /* Load curthread value */
3:
/*
* Load the kernel GP value.
*/
la gp, _gp
/*
* Prepare to call mips_trap(struct trapframe *)
*/
addiu a0, sp, 16 /* set argument - pointer to the trapframe */
jal mips_trap /* call it */
nop /* delay slot */
/* Something must be here or gdb doesn't find the stack frame. */
nop
/*
* Now restore stuff and return from the exception.
* Interrupts should be off.
*/
exception_return:
/* 16(sp) no need to restore tf_vaddr */
lw t0, 20(sp) /* load status register value into t0 */
nop /* load delay slot */
mtc0 t0, c0_status /* store it back to coprocessor 0 */
/* 24(sp) no need to restore tf_cause */
/* restore special registers */
lw t1, 28(sp)
lw t0, 32(sp)
mtlo t1
mthi t0
/* load the general registers */
lw ra, 36(sp)
lw AT, 40(sp)
lw v0, 44(sp)
lw v1, 48(sp)
lw a0, 52(sp)
lw a1, 56(sp)
lw a2, 60(sp)
lw a3, 64(sp)
lw t0, 68(sp)
lw t1, 72(sp)
lw t2, 76(sp)
lw t3, 80(sp)
lw t4, 84(sp)
lw t5, 88(sp)
lw t6, 92(sp)
lw t7, 96(sp)
lw s0, 100(sp)
lw s1, 104(sp)
lw s2, 108(sp)
lw s3, 112(sp)
lw s4, 116(sp)
lw s5, 120(sp)
lw s6, 124(sp)
lw s7, 128(sp)
lw t8, 132(sp)
lw t9, 136(sp)
/* 140(sp) "saved" k0 was dummy garbage anyway */
/* 144(sp) "saved" k1 was dummy garbage anyway */
lw gp, 148(sp) /* restore gp */
/* 152(sp) stack pointer - below */
lw s8, 156(sp) /* restore s8 */
lw k0, 160(sp) /* fetch exception return PC into k0 */
lw sp, 152(sp) /* fetch saved sp (must be last) */
/* done */
jr k0 /* jump back */
rfe /* in delay slot */
.end common_exception
/*
* Code to enter user mode for the first time.
* Does not return.
*
* This is called from mips_usermode().
* Interrupts on this processor should be off.
*/
.text
.globl asm_usermode
.type asm_usermode,@function
.ent asm_usermode
asm_usermode:
/*
* a0 is the address of a trapframe to use for exception "return".
* It's allocated on our stack.
*
* Move it to the stack pointer - we don't need the actual stack
* position any more. (When we come back from usermode, cpustacks[]
* will be used to reinitialize our stack pointer, and that was
* set by mips_usermode.)
*
* Then just jump to the exception return code above.
*/
j exception_return
addiu sp, a0, -16 /* in delay slot */
.end asm_usermode

View File

@@ -0,0 +1,438 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <signal.h>
#include <lib.h>
#include <mips/specialreg.h>
#include <mips/trapframe.h>
#include <cpu.h>
#include <spl.h>
#include <thread.h>
#include <current.h>
#include <vm.h>
#include <mainbus.h>
#include <syscall.h>
/* in exception-*.S */
extern __DEAD void asm_usermode(struct trapframe *tf);
/* called only from assembler, so not declared in a header */
void mips_trap(struct trapframe *tf);
/* Names for trap codes */
#define NTRAPCODES 13
static const char *const trapcodenames[NTRAPCODES] = {
"Interrupt",
"TLB modify trap",
"TLB miss on load",
"TLB miss on store",
"Address error on load",
"Address error on store",
"Bus error on code",
"Bus error on data",
"System call",
"Break instruction",
"Illegal instruction",
"Coprocessor unusable",
"Arithmetic overflow",
};
/*
* Function called when user-level code hits a fatal fault.
*/
static
void
kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr)
{
int sig = 0;
KASSERT(code < NTRAPCODES);
switch (code) {
case EX_IRQ:
case EX_IBE:
case EX_DBE:
case EX_SYS:
/* should not be seen */
KASSERT(0);
sig = SIGABRT;
break;
case EX_MOD:
case EX_TLBL:
case EX_TLBS:
sig = SIGSEGV;
break;
case EX_ADEL:
case EX_ADES:
sig = SIGBUS;
break;
case EX_BP:
sig = SIGTRAP;
break;
case EX_RI:
sig = SIGILL;
break;
case EX_CPU:
sig = SIGSEGV;
break;
case EX_OVF:
sig = SIGFPE;
break;
}
/*
* You will probably want to change this.
*/
kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n",
code, sig, trapcodenames[code], epc, vaddr);
panic("I don't know how to handle this\n");
}
/*
* General trap (exception) handling function for mips.
* This is called by the assembly-language exception handler once
* the trapframe has been set up.
*/
void
mips_trap(struct trapframe *tf)
{
uint32_t code;
/*bool isutlb; -- not used */
bool iskern;
int spl;
/* The trap frame is supposed to be 37 registers long. */
KASSERT(sizeof(struct trapframe)==(37*4));
/*
* Extract the exception code info from the register fields.
*/
code = (tf->tf_cause & CCA_CODE) >> CCA_CODESHIFT;
/*isutlb = (tf->tf_cause & CCA_UTLB) != 0;*/
iskern = (tf->tf_status & CST_KUp) == 0;
KASSERT(code < NTRAPCODES);
/* Make sure we haven't run off our stack */
if (curthread != NULL && curthread->t_stack != NULL) {
KASSERT((vaddr_t)tf > (vaddr_t)curthread->t_stack);
KASSERT((vaddr_t)tf < (vaddr_t)(curthread->t_stack
+ STACK_SIZE));
}
/* Interrupt? Call the interrupt handler and return. */
if (code == EX_IRQ) {
int old_in;
bool doadjust;
old_in = curthread->t_in_interrupt;
curthread->t_in_interrupt = 1;
/*
* The processor has turned interrupts off; if the
* currently recorded interrupt state is interrupts on
* (spl of 0), adjust the recorded state to match, and
* restore after processing the interrupt.
*
* How can we get an interrupt if the recorded state
* is interrupts off? Well, as things currently stand
* when the CPU finishes idling it flips interrupts on
* and off to allow things to happen, but leaves
* curspl high while doing so.
*
* While we're here, assert that the interrupt
* handling code hasn't leaked a spinlock or an
* splhigh().
*/
if (curthread->t_curspl == 0) {
KASSERT(curthread->t_curspl == 0);
KASSERT(curthread->t_iplhigh_count == 0);
curthread->t_curspl = IPL_HIGH;
curthread->t_iplhigh_count++;
doadjust = true;
}
else {
doadjust = false;
}
mainbus_interrupt(tf);
if (doadjust) {
KASSERT(curthread->t_curspl == IPL_HIGH);
KASSERT(curthread->t_iplhigh_count == 1);
curthread->t_iplhigh_count--;
curthread->t_curspl = 0;
}
curthread->t_in_interrupt = old_in;
goto done2;
}
/*
* The processor turned interrupts off when it took the trap.
*
* While we're in the kernel, and not actually handling an
* interrupt, restore the interrupt state to where it was in
* the previous context, which may be low (interrupts on).
*
* Do this by forcing splhigh(), which may do a redundant
* cpu_irqoff() but forces the stored MI interrupt state into
* sync, then restoring the previous state.
*/
spl = splhigh();
splx(spl);
/* Syscall? Call the syscall handler and return. */
if (code == EX_SYS) {
/* Interrupts should have been on while in user mode. */
KASSERT(curthread->t_curspl == 0);
KASSERT(curthread->t_iplhigh_count == 0);
DEBUG(DB_SYSCALL, "syscall: #%d, args %x %x %x %x\n",
tf->tf_v0, tf->tf_a0, tf->tf_a1, tf->tf_a2, tf->tf_a3);
syscall(tf);
goto done;
}
/*
* Ok, it wasn't any of the really easy cases.
* Call vm_fault on the TLB exceptions.
* Panic on the bus error exceptions.
*/
switch (code) {
case EX_MOD:
if (vm_fault(VM_FAULT_READONLY, tf->tf_vaddr)==0) {
goto done;
}
break;
case EX_TLBL:
if (vm_fault(VM_FAULT_READ, tf->tf_vaddr)==0) {
goto done;
}
break;
case EX_TLBS:
if (vm_fault(VM_FAULT_WRITE, tf->tf_vaddr)==0) {
goto done;
}
break;
case EX_IBE:
case EX_DBE:
/*
* This means you loaded invalid TLB entries, or
* touched invalid parts of the direct-mapped
* segments. These are serious kernel errors, so
* panic.
*
* The MIPS won't even tell you what invalid address
* caused the bus error.
*/
panic("Bus error exception, PC=0x%x\n", tf->tf_epc);
break;
}
/*
* If we get to this point, it's a fatal fault - either it's
* one of the other exceptions, like illegal instruction, or
* it was a page fault we couldn't handle.
*/
if (!iskern) {
/*
* Fatal fault in user mode.
* Kill the current user process.
*/
kill_curthread(tf->tf_epc, code, tf->tf_vaddr);
goto done;
}
/*
* Fatal fault in kernel mode.
*
* If pcb_badfaultfunc is set, we do not panic; badfaultfunc is
* set by copyin/copyout and related functions to signify that
* the addresses they're accessing are userlevel-supplied and
* not trustable. What we actually want to do is resume
* execution at the function pointed to by badfaultfunc. That's
* going to be "copyfail" (see copyinout.c), which longjmps
* back to copyin/copyout or wherever and returns EFAULT.
*
* Note that we do not just *call* this function, because that
* won't necessarily do anything. We want the control flow
* that is currently executing in copyin (or whichever), and
* is stopped while we process the exception, to *teleport* to
* copyfail.
*
* This is accomplished by changing tf->tf_epc and returning
* from the exception handler.
*/
if (curthread != NULL &&
curthread->t_machdep.tm_badfaultfunc != NULL) {
tf->tf_epc = (vaddr_t) curthread->t_machdep.tm_badfaultfunc;
goto done;
}
/*
* Really fatal kernel-mode fault.
*/
kprintf("panic: Fatal exception %u (%s) in kernel mode\n", code,
trapcodenames[code]);
kprintf("panic: EPC 0x%x, exception vaddr 0x%x\n",
tf->tf_epc, tf->tf_vaddr);
panic("I can't handle this... I think I'll just die now...\n");
done:
/*
* Turn interrupts off on the processor, without affecting the
* stored interrupt state.
*/
cpu_irqoff();
done2:
/*
* The boot thread can get here (e.g. on interrupt return) but
* since it doesn't go to userlevel, it can't be returning to
* userlevel, so there's no need to set cputhreads[] and
* cpustacks[]. Just return.
*/
if (curthread->t_stack == NULL) {
return;
}
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
/*
* This assertion will fail if either
* (1) curthread->t_stack is corrupted, or
* (2) the trap frame is somehow on the wrong kernel stack.
*
* If cpustacks[] is corrupted, the next trap back to the
* kernel will (most likely) hang the system, so it's better
* to find out now.
*/
KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
}
/*
* Function for entering user mode.
*
* This should not be used by threads returning from traps - they
* should just return from mips_trap(). It should be used by threads
* entering user mode for the first time - whether the child thread in
* a fork(), or into a brand-new address space after exec(), or when
* starting the first userlevel program.
*
* It works by jumping into the exception return code.
*
* mips_usermode is common code for this. It cannot usefully be called
* outside the mips port, but should be called from one of the
* following places:
* - enter_new_process, for use by exec and equivalent.
* - enter_forked_process, in syscall.c, for use by fork.
*/
void
mips_usermode(struct trapframe *tf)
{
/*
* Interrupts should be off within the kernel while entering
* user mode. However, while in user mode, interrupts should
* be on. To interact properly with the spl-handling logic
* above, we explicitly call spl0() and then call cpu_irqoff().
*/
spl0();
cpu_irqoff();
cputhreads[curcpu->c_number] = (vaddr_t)curthread;
cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
/*
* This assertion will fail if either
* (1) cpustacks[] is corrupted, or
* (2) the trap frame is not on our own kernel stack, or
* (3) the boot thread tries to enter user mode.
*
* If cpustacks[] is corrupted, the next trap back to the
* kernel will (most likely) hang the system, so it's better
* to find out now.
*
* It's necessary for the trap frame used here to be on the
* current thread's own stack. It cannot correctly be on
* either another thread's stack or in the kernel heap.
* (Exercise: why?)
*/
KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
/*
* This actually does it. See exception-*.S.
*/
asm_usermode(tf);
}
/*
* enter_new_process: go to user mode after loading an executable.
*
* Performs the necessary initialization so that the user program will
* get the arguments supplied in argc/argv (note that argv must be a
* user-level address) and the environment pointer env (ditto), and
* begin executing at the specified entry point. The stack pointer is
* initialized from the stackptr argument. Note that passing argc/argv
* may use additional stack space on some other platforms (but not on
* mips).
*
* Unless you implement execve() that passes environments around, just
* pass NULL for the environment.
*
* Works by creating an ersatz trapframe.
*/
void
enter_new_process(int argc, userptr_t argv, userptr_t env,
vaddr_t stack, vaddr_t entry)
{
struct trapframe tf;
bzero(&tf, sizeof(tf));
tf.tf_status = CST_IRQMASK | CST_IEp | CST_KUp;
tf.tf_epc = entry;
tf.tf_a0 = argc;
tf.tf_a1 = (vaddr_t)argv;
tf.tf_a2 = (vaddr_t)env;
tf.tf_sp = stack;
mips_usermode(&tf);
}

View File

@@ -0,0 +1,161 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <kern/errno.h>
#include <kern/syscall.h>
#include <lib.h>
#include <mips/trapframe.h>
#include <thread.h>
#include <current.h>
#include <syscall.h>
/*
* System call dispatcher.
*
* A pointer to the trapframe created during exception entry (in
* exception-*.S) is passed in.
*
* The calling conventions for syscalls are as follows: Like ordinary
* function calls, the first 4 32-bit arguments are passed in the 4
* argument registers a0-a3. 64-bit arguments are passed in *aligned*
* pairs of registers, that is, either a0/a1 or a2/a3. This means that
* if the first argument is 32-bit and the second is 64-bit, a1 is
* unused.
*
* This much is the same as the calling conventions for ordinary
* function calls. In addition, the system call number is passed in
* the v0 register.
*
* On successful return, the return value is passed back in the v0
* register, or v0 and v1 if 64-bit. This is also like an ordinary
* function call, and additionally the a3 register is also set to 0 to
* indicate success.
*
* On an error return, the error code is passed back in the v0
* register, and the a3 register is set to 1 to indicate failure.
* (Userlevel code takes care of storing the error code in errno and
* returning the value -1 from the actual userlevel syscall function.
* See src/user/lib/libc/arch/mips/syscalls-mips.S and related files.)
*
* Upon syscall return the program counter stored in the trapframe
* must be incremented by one instruction; otherwise the exception
* return code will restart the "syscall" instruction and the system
* call will repeat forever.
*
* If you run out of registers (which happens quickly with 64-bit
* values) further arguments must be fetched from the user-level
* stack, starting at sp+16 to skip over the slots for the
* registerized values, with copyin().
*/
void
syscall(struct trapframe *tf)
{
int callno;
int32_t retval;
int err;
KASSERT(curthread != NULL);
KASSERT(curthread->t_curspl == 0);
KASSERT(curthread->t_iplhigh_count == 0);
callno = tf->tf_v0;
/*
* Initialize retval to 0. Many of the system calls don't
* really return a value, just 0 for success and -1 on
* error. Since retval is the value returned on success,
* initialize it to 0 by default; thus it's not necessary to
* deal with it except for calls that return other values,
* like write.
*/
retval = 0;
switch (callno) {
case SYS_reboot:
err = sys_reboot(tf->tf_a0);
break;
case SYS___time:
err = sys___time((userptr_t)tf->tf_a0,
(userptr_t)tf->tf_a1);
break;
/* Add stuff here */
default:
kprintf("Unknown syscall %d\n", callno);
err = ENOSYS;
break;
}
if (err) {
/*
* Return the error code. This gets converted at
* userlevel to a return value of -1 and the error
* code in errno.
*/
tf->tf_v0 = err;
tf->tf_a3 = 1; /* signal an error */
}
else {
/* Success. */
tf->tf_v0 = retval;
tf->tf_a3 = 0; /* signal no error */
}
/*
* Now, advance the program counter, to avoid restarting
* the syscall over and over again.
*/
tf->tf_epc += 4;
/* Make sure the syscall code didn't forget to lower spl */
KASSERT(curthread->t_curspl == 0);
/* ...or leak any spinlocks */
KASSERT(curthread->t_iplhigh_count == 0);
}
/*
* Enter user mode for a newly forked process.
*
* This function is provided as a reminder. You need to write
* both it and the code that calls it.
*
* Thus, you can trash it and do things another way if you prefer.
*/
void
enter_forked_process(struct trapframe *tf)
{
(void)tf;
}

301
kern/arch/mips/thread/cpu.c Normal file
View File

@@ -0,0 +1,301 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* CPU control functions.
*/
#include <types.h>
#include <lib.h>
#include <mips/specialreg.h>
#include <mips/trapframe.h>
#include <platform/maxcpus.h>
#include <cpu.h>
#include <thread.h>
////////////////////////////////////////////////////////////
/*
* Startup and exception-time stack hook.
*
* The MIPS lacks a good way to find the current CPU, current thread,
* or current thread stack upon trap entry from user mode. To deal
* with this, we store the CPU number (our number, not the hardware
* number) in a nonessential field in the MMU, which is about the only
* place possible, and then use that to index cpustacks[]. This gets
* us the value to load as the stack pointer. We can then also load
* curthread from cputhreads[] by parallel indexing.
*
* These arrays are also used to start up new CPUs, for roughly the
* same reasons.
*/
vaddr_t cpustacks[MAXCPUS];
vaddr_t cputhreads[MAXCPUS];
/*
* Do machine-dependent initialization of the cpu structure or things
* associated with a new cpu. Note that we're not running on the new
* cpu when this is called.
*/
void
cpu_machdep_init(struct cpu *c)
{
vaddr_t stackpointer;
KASSERT(c->c_number < MAXCPUS);
if (c->c_curthread->t_stack == NULL) {
/* boot cpu; don't need to do anything here */
}
else {
/*
* Stick the stack in cpustacks[], and thread pointer
* in cputhreads[].
*/
/* stack base address */
stackpointer = (vaddr_t) c->c_curthread->t_stack;
/* since stacks grow down, get the top */
stackpointer += STACK_SIZE;
cpustacks[c->c_number] = stackpointer;
cputhreads[c->c_number] = (vaddr_t)c->c_curthread;
}
}
////////////////////////////////////////////////////////////
/*
* Return the type name of the currently running CPU.
*
* For now, assume we're running on System/161 so we can use the
* System/161 processor-ID values.
*/
#define SYS161_PRID_ORIG 0x000003ff
#define SYS161_PRID_2X 0x000000a1
static inline
uint32_t
cpu_getprid(void)
{
uint32_t prid;
__asm volatile("mfc0 %0,$15" : "=r" (prid));
return prid;
}
static inline
uint32_t
cpu_getfeatures(void)
{
uint32_t features;
__asm volatile(".set push;" /* save assembler mode */
".set mips32;" /* allow mips32 instructions */
"mfc0 %0,$15,1;" /* get cop0 reg 15 sel 1 */
".set pop" /* restore assembler mode */
: "=r" (features));
return features;
}
static inline
uint32_t
cpu_getifeatures(void)
{
uint32_t features;
__asm volatile(".set push;" /* save assembler mode */
".set mips32;" /* allow mips32 instructions */
"mfc0 %0,$15,2;" /* get cop0 reg 15 sel 2 */
".set pop" /* restore assembler mode */
: "=r" (features));
return features;
}
void
cpu_identify(char *buf, size_t max)
{
uint32_t prid;
uint32_t features;
prid = cpu_getprid();
switch (prid) {
case SYS161_PRID_ORIG:
snprintf(buf, max, "MIPS/161 (System/161 1.x and pre-2.x)");
break;
case SYS161_PRID_2X:
features = cpu_getfeatures();
snprintf(buf, max, "MIPS/161 (System/161 2.x) features 0x%x",
features);
features = cpu_getifeatures();
if (features != 0) {
kprintf("WARNING: unknown CPU incompatible features "
"0x%x\n", features);
}
break;
default:
snprintf(buf, max, "32-bit MIPS (unknown type, CPU ID 0x%x)",
prid);
break;
}
}
////////////////////////////////////////////////////////////
/*
* Interrupt control.
*
* While the mips actually has on-chip interrupt priority masking, in
* the interests of simplicity, we don't use it. Instead we use
* coprocessor 0 register 12 (the system coprocessor "status"
* register) bit 0, IEc, which is the global interrupt enable flag.
* (IEc stands for interrupt-enable-current.)
*/
/*
* gcc inline assembly to get at the status register.
*
* Pipeline hazards:
* - there must be at least one cycle between GET_STATUS
* and SET_STATUS;
* - it may take up to three cycles after SET_STATUS for the
* interrupt state to really change.
*
* These considerations do not (currently) apply to System/161,
* however.
*/
#define GET_STATUS(x) __asm volatile("mfc0 %0,$12" : "=r" (x))
#define SET_STATUS(x) __asm volatile("mtc0 %0,$12" :: "r" (x))
/*
* Interrupts on.
*/
void
cpu_irqon(void)
{
uint32_t x;
GET_STATUS(x);
x |= CST_IEc;
SET_STATUS(x);
}
/*
* Interrupts off.
*/
void
cpu_irqoff(void)
{
uint32_t x;
GET_STATUS(x);
x &= ~(uint32_t)CST_IEc;
SET_STATUS(x);
}
/*
* Used below.
*/
static
void
cpu_irqonoff(void)
{
uint32_t x, xon, xoff;
GET_STATUS(x);
xon = x | CST_IEc;
xoff = x & ~(uint32_t)CST_IEc;
SET_STATUS(xon);
__asm volatile("nop; nop; nop; nop");
SET_STATUS(xoff);
}
////////////////////////////////////////////////////////////
/*
* Idling.
*/
/*
* gcc inline assembly for the WAIT instruction.
*
* mips r2k/r3k has no idle instruction at all.
*
* However, to avoid completely overloading the computing cluster, we
* appropriate the mips32 WAIT instruction.
*/
static
inline
void
wait(void)
{
/*
* The WAIT instruction goes into powersave mode until an
* interrupt is trying to occur.
*
* Then switch interrupts on and off again, so we actually
* take the interrupt.
*
* Note that the precise behavior of this instruction in the
* System/161 simulator is partly guesswork. This code may not
* work on a real mips.
*/
__asm volatile(
".set push;" /* save assembler mode */
".set mips32;" /* allow MIPS32 instructions */
".set volatile;" /* avoid unwanted optimization */
"wait;" /* suspend until interrupted */
".set pop" /* restore assembler mode */
);
}
/*
* Idle the processor until something happens.
*/
void
cpu_idle(void)
{
wait();
cpu_irqonoff();
}
/*
* Halt the CPU permanently.
*/
void
cpu_halt(void)
{
cpu_irqoff();
while (1) {
wait();
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Assembly language context switch code.
*/
#include <kern/mips/regdefs.h>
.text
.set noreorder
.globl switchframe_switch
.type switchframe_switch,@function
.ent switchframe_switch
switchframe_switch:
/*
* a0 contains the address of the switchframe pointer in the old thread.
* a1 contains the address of the switchframe pointer in the new thread.
*
* The switchframe pointer is really the stack pointer. The other
* registers get saved on the stack, namely:
*
* s0-s6, s8
* gp, ra
*
* The order must match <mips/switchframe.h>.
*
* Note that while we'd ordinarily need to save s7 too, because we
* use it to hold curthread saving it would interfere with the way
* curthread is managed by thread.c. So we'll just let thread.c
* manage it.
*/
/* Allocate stack space for saving 10 registers. 10*4 = 40 */
addi sp, sp, -40
/* Save the registers */
sw ra, 36(sp)
sw gp, 32(sp)
sw s8, 28(sp)
sw s6, 24(sp)
sw s5, 20(sp)
sw s4, 16(sp)
sw s3, 12(sp)
sw s2, 8(sp)
sw s1, 4(sp)
sw s0, 0(sp)
/* Store the old stack pointer in the old thread */
sw sp, 0(a0)
/* Get the new stack pointer from the new thread */
lw sp, 0(a1)
nop /* delay slot for load */
/* Now, restore the registers */
lw s0, 0(sp)
lw s1, 4(sp)
lw s2, 8(sp)
lw s3, 12(sp)
lw s4, 16(sp)
lw s5, 20(sp)
lw s6, 24(sp)
lw s8, 28(sp)
lw gp, 32(sp)
lw ra, 36(sp)
nop /* delay slot for load */
/* and return. */
j ra
addi sp, sp, 40 /* in delay slot */
.end switchframe_switch

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <lib.h>
#include <thread.h>
#include <threadprivate.h>
#include "switchframe.h"
/* in threadstart.S */
extern void mips_threadstart(/* arguments are in unusual registers */);
/*
* Function to initialize the switchframe of a new thread, which is
* *not* the one that is currently running.
*
* The new thread should, when it is run the first time, end up calling
* thread_startup(entrypoint, data1, data2).
*
* We arrange for this by creating a phony switchframe for
* switchframe_switch() to switch to. The only trouble is that the
* switchframe doesn't include the argument registers a0-a3. So we
* store the arguments in the s* registers, and use a bit of asm
* (mips_threadstart) to move them and then jump to thread_startup.
*/
void
switchframe_init(struct thread *thread,
void (*entrypoint)(void *data1, unsigned long data2),
void *data1, unsigned long data2)
{
vaddr_t stacktop;
struct switchframe *sf;
/*
* MIPS stacks grow down. t_stack is just a hunk of memory, so
* get the other end of it. Then set up a switchframe on the
* top of the stack.
*/
stacktop = ((vaddr_t)thread->t_stack) + STACK_SIZE;
sf = ((struct switchframe *) stacktop) - 1;
/* Zero out the switchframe. */
bzero(sf, sizeof(*sf));
/*
* Now set the important parts: pass through the three arguments,
* and set the return address register to the place we want
* execution to begin.
*
* Thus, when switchframe_switch does its "j ra", it will
* actually jump to mips_threadstart, which will move the
* arguments into the right register and jump to
* thread_startup().
*
* Note that this means that when we call switchframe_switch()
* in thread_switch(), we may not come back out the same way
* in the next thread. (Though we will come back out the same
* way when we later come back to the same thread again.)
*
* This has implications for code at the bottom of
* thread_switch, described in thread.c.
*/
sf->sf_s0 = (uint32_t)entrypoint;
sf->sf_s1 = (uint32_t)data1;
sf->sf_s2 = (uint32_t)data2;
sf->sf_ra = (uint32_t)mips_threadstart;
/* Set ->t_context, and we're done. */
thread->t_context = sf;
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _MIPS_SWITCHFRAME_H_
#define _MIPS_SWITCHFRAME_H_
/*
* Structure describing what is saved on the stack during a context switch.
*
* This must agree with the code in switch.S.
*/
struct switchframe {
uint32_t sf_s0;
uint32_t sf_s1;
uint32_t sf_s2;
uint32_t sf_s3;
uint32_t sf_s4;
uint32_t sf_s5;
uint32_t sf_s6;
uint32_t sf_s8;
uint32_t sf_gp;
uint32_t sf_ra;
};
#endif /* _MIPS_SWITCHFRAME_H_ */

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Functions for handling struct thread_machdep.
*/
#include <types.h>
#include <lib.h>
#include <thread.h>
#include <threadprivate.h>
void
thread_machdep_init(struct thread_machdep *tm)
{
tm->tm_badfaultfunc = NULL;
}
void
thread_machdep_cleanup(struct thread_machdep *tm)
{
KASSERT(tm->tm_badfaultfunc == NULL);
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Assembler-level thread startup trampoline.
*/
#include <kern/mips/regdefs.h>
.text
.set noreorder
.globl mips_threadstart
.type mips_threadstart,@function
.ent mips_threadstart
mips_threadstart:
/*
* This code doesn't take normal arguments. It's reached when
* switchframe_switch switches to a new thread. switchframe_switch
* does "j ra"; ra gets preloaded in switchframe_init to come here.
*
* Our arguments are in callee-save registers, as follows:
*
* s0 entrypoint
* s1 data1
* s2 data2
*
* We need to rearrange these so as to call the normal C function
* thread_startup(void (*entrypoint)(), void *data1, unsigned long data2).
*/
addiu sp, sp, -16 /* make our stack frame */
move ra, $0 /* clear return addr so we're top of the call stack */
move a0, s0 /* load arguments and call */
move a1, s1
j thread_startup
move a2, s2 /* (in delay slot) */
.end mips_threadstart

433
kern/arch/mips/vm/dumbvm.c Normal file
View File

@@ -0,0 +1,433 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <kern/errno.h>
#include <lib.h>
#include <spl.h>
#include <cpu.h>
#include <spinlock.h>
#include <proc.h>
#include <current.h>
#include <mips/tlb.h>
#include <addrspace.h>
#include <vm.h>
/*
* Dumb MIPS-only "VM system" that is intended to only be just barely
* enough to struggle off the ground. You should replace all of this
* code while doing the VM assignment. In fact, starting in that
* assignment, this file is not included in your kernel!
*
* NOTE: it's been found over the years that students often begin on
* the VM assignment by copying dumbvm.c and trying to improve it.
* This is not recommended. dumbvm is (more or less intentionally) not
* a good design reference. The first recommendation would be: do not
* look at dumbvm at all. The second recommendation would be: if you
* do, be sure to review it from the perspective of comparing it to
* what a VM system is supposed to do, and understanding what corners
* it's cutting (there are many) and why, and more importantly, how.
*/
/* under dumbvm, always have 72k of user stack */
/* (this must be > 64K so argument blocks of size ARG_MAX will fit) */
#define DUMBVM_STACKPAGES 18
/*
* Wrap ram_stealmem in a spinlock.
*/
static struct spinlock stealmem_lock = SPINLOCK_INITIALIZER;
void
vm_bootstrap(void)
{
/* Do nothing. */
}
/*
* Check if we're in a context that can sleep. While most of the
* operations in dumbvm don't in fact sleep, in a real VM system many
* of them would. In those, assert that sleeping is ok. This helps
* avoid the situation where syscall-layer code that works ok with
* dumbvm starts blowing up during the VM assignment.
*/
static
void
dumbvm_can_sleep(void)
{
if (CURCPU_EXISTS()) {
/* must not hold spinlocks */
KASSERT(curcpu->c_spinlocks == 0);
/* must not be in an interrupt handler */
KASSERT(curthread->t_in_interrupt == 0);
}
}
static
paddr_t
getppages(unsigned long npages)
{
paddr_t addr;
spinlock_acquire(&stealmem_lock);
addr = ram_stealmem(npages);
spinlock_release(&stealmem_lock);
return addr;
}
/* Allocate/free some kernel-space virtual pages */
vaddr_t
alloc_kpages(unsigned npages)
{
paddr_t pa;
dumbvm_can_sleep();
pa = getppages(npages);
if (pa==0) {
return 0;
}
return PADDR_TO_KVADDR(pa);
}
void
free_kpages(vaddr_t addr)
{
/* nothing - leak the memory. */
(void)addr;
}
void
vm_tlbshootdown_all(void)
{
panic("dumbvm tried to do tlb shootdown?!\n");
}
void
vm_tlbshootdown(const struct tlbshootdown *ts)
{
(void)ts;
panic("dumbvm tried to do tlb shootdown?!\n");
}
int
vm_fault(int faulttype, vaddr_t faultaddress)
{
vaddr_t vbase1, vtop1, vbase2, vtop2, stackbase, stacktop;
paddr_t paddr;
int i;
uint32_t ehi, elo;
struct addrspace *as;
int spl;
faultaddress &= PAGE_FRAME;
DEBUG(DB_VM, "dumbvm: fault: 0x%x\n", faultaddress);
switch (faulttype) {
case VM_FAULT_READONLY:
/* We always create pages read-write, so we can't get this */
panic("dumbvm: got VM_FAULT_READONLY\n");
case VM_FAULT_READ:
case VM_FAULT_WRITE:
break;
default:
return EINVAL;
}
if (curproc == NULL) {
/*
* No process. This is probably a kernel fault early
* in boot. Return EFAULT so as to panic instead of
* getting into an infinite faulting loop.
*/
return EFAULT;
}
as = proc_getas();
if (as == NULL) {
/*
* No address space set up. This is probably also a
* kernel fault early in boot.
*/
return EFAULT;
}
/* Assert that the address space has been set up properly. */
KASSERT(as->as_vbase1 != 0);
KASSERT(as->as_pbase1 != 0);
KASSERT(as->as_npages1 != 0);
KASSERT(as->as_vbase2 != 0);
KASSERT(as->as_pbase2 != 0);
KASSERT(as->as_npages2 != 0);
KASSERT(as->as_stackpbase != 0);
KASSERT((as->as_vbase1 & PAGE_FRAME) == as->as_vbase1);
KASSERT((as->as_pbase1 & PAGE_FRAME) == as->as_pbase1);
KASSERT((as->as_vbase2 & PAGE_FRAME) == as->as_vbase2);
KASSERT((as->as_pbase2 & PAGE_FRAME) == as->as_pbase2);
KASSERT((as->as_stackpbase & PAGE_FRAME) == as->as_stackpbase);
vbase1 = as->as_vbase1;
vtop1 = vbase1 + as->as_npages1 * PAGE_SIZE;
vbase2 = as->as_vbase2;
vtop2 = vbase2 + as->as_npages2 * PAGE_SIZE;
stackbase = USERSTACK - DUMBVM_STACKPAGES * PAGE_SIZE;
stacktop = USERSTACK;
if (faultaddress >= vbase1 && faultaddress < vtop1) {
paddr = (faultaddress - vbase1) + as->as_pbase1;
}
else if (faultaddress >= vbase2 && faultaddress < vtop2) {
paddr = (faultaddress - vbase2) + as->as_pbase2;
}
else if (faultaddress >= stackbase && faultaddress < stacktop) {
paddr = (faultaddress - stackbase) + as->as_stackpbase;
}
else {
return EFAULT;
}
/* make sure it's page-aligned */
KASSERT((paddr & PAGE_FRAME) == paddr);
/* Disable interrupts on this CPU while frobbing the TLB. */
spl = splhigh();
for (i=0; i<NUM_TLB; i++) {
tlb_read(&ehi, &elo, i);
if (elo & TLBLO_VALID) {
continue;
}
ehi = faultaddress;
elo = paddr | TLBLO_DIRTY | TLBLO_VALID;
DEBUG(DB_VM, "dumbvm: 0x%x -> 0x%x\n", faultaddress, paddr);
tlb_write(ehi, elo, i);
splx(spl);
return 0;
}
kprintf("dumbvm: Ran out of TLB entries - cannot handle page fault\n");
splx(spl);
return EFAULT;
}
struct addrspace *
as_create(void)
{
struct addrspace *as = kmalloc(sizeof(struct addrspace));
if (as==NULL) {
return NULL;
}
as->as_vbase1 = 0;
as->as_pbase1 = 0;
as->as_npages1 = 0;
as->as_vbase2 = 0;
as->as_pbase2 = 0;
as->as_npages2 = 0;
as->as_stackpbase = 0;
return as;
}
void
as_destroy(struct addrspace *as)
{
dumbvm_can_sleep();
kfree(as);
}
void
as_activate(void)
{
int i, spl;
struct addrspace *as;
as = proc_getas();
if (as == NULL) {
return;
}
/* Disable interrupts on this CPU while frobbing the TLB. */
spl = splhigh();
for (i=0; i<NUM_TLB; i++) {
tlb_write(TLBHI_INVALID(i), TLBLO_INVALID(), i);
}
splx(spl);
}
void
as_deactivate(void)
{
/* nothing */
}
int
as_define_region(struct addrspace *as, vaddr_t vaddr, size_t sz,
int readable, int writeable, int executable)
{
size_t npages;
dumbvm_can_sleep();
/* Align the region. First, the base... */
sz += vaddr & ~(vaddr_t)PAGE_FRAME;
vaddr &= PAGE_FRAME;
/* ...and now the length. */
sz = (sz + PAGE_SIZE - 1) & PAGE_FRAME;
npages = sz / PAGE_SIZE;
/* We don't use these - all pages are read-write */
(void)readable;
(void)writeable;
(void)executable;
if (as->as_vbase1 == 0) {
as->as_vbase1 = vaddr;
as->as_npages1 = npages;
return 0;
}
if (as->as_vbase2 == 0) {
as->as_vbase2 = vaddr;
as->as_npages2 = npages;
return 0;
}
/*
* Support for more than two regions is not available.
*/
kprintf("dumbvm: Warning: too many regions\n");
return ENOSYS;
}
static
void
as_zero_region(paddr_t paddr, unsigned npages)
{
bzero((void *)PADDR_TO_KVADDR(paddr), npages * PAGE_SIZE);
}
int
as_prepare_load(struct addrspace *as)
{
KASSERT(as->as_pbase1 == 0);
KASSERT(as->as_pbase2 == 0);
KASSERT(as->as_stackpbase == 0);
dumbvm_can_sleep();
as->as_pbase1 = getppages(as->as_npages1);
if (as->as_pbase1 == 0) {
return ENOMEM;
}
as->as_pbase2 = getppages(as->as_npages2);
if (as->as_pbase2 == 0) {
return ENOMEM;
}
as->as_stackpbase = getppages(DUMBVM_STACKPAGES);
if (as->as_stackpbase == 0) {
return ENOMEM;
}
as_zero_region(as->as_pbase1, as->as_npages1);
as_zero_region(as->as_pbase2, as->as_npages2);
as_zero_region(as->as_stackpbase, DUMBVM_STACKPAGES);
return 0;
}
int
as_complete_load(struct addrspace *as)
{
dumbvm_can_sleep();
(void)as;
return 0;
}
int
as_define_stack(struct addrspace *as, vaddr_t *stackptr)
{
KASSERT(as->as_stackpbase != 0);
*stackptr = USERSTACK;
return 0;
}
int
as_copy(struct addrspace *old, struct addrspace **ret)
{
struct addrspace *new;
dumbvm_can_sleep();
new = as_create();
if (new==NULL) {
return ENOMEM;
}
new->as_vbase1 = old->as_vbase1;
new->as_npages1 = old->as_npages1;
new->as_vbase2 = old->as_vbase2;
new->as_npages2 = old->as_npages2;
/* (Mis)use as_prepare_load to allocate some physical memory. */
if (as_prepare_load(new)) {
as_destroy(new);
return ENOMEM;
}
KASSERT(new->as_pbase1 != 0);
KASSERT(new->as_pbase2 != 0);
KASSERT(new->as_stackpbase != 0);
memmove((void *)PADDR_TO_KVADDR(new->as_pbase1),
(const void *)PADDR_TO_KVADDR(old->as_pbase1),
old->as_npages1*PAGE_SIZE);
memmove((void *)PADDR_TO_KVADDR(new->as_pbase2),
(const void *)PADDR_TO_KVADDR(old->as_pbase2),
old->as_npages2*PAGE_SIZE);
memmove((void *)PADDR_TO_KVADDR(new->as_stackpbase),
(const void *)PADDR_TO_KVADDR(old->as_stackpbase),
DUMBVM_STACKPAGES*PAGE_SIZE);
*ret = new;
return 0;
}

153
kern/arch/mips/vm/ram.c Normal file
View File

@@ -0,0 +1,153 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <lib.h>
#include <vm.h>
#include <mainbus.h>
vaddr_t firstfree; /* first free virtual address; set by start.S */
static paddr_t firstpaddr; /* address of first free physical page */
static paddr_t lastpaddr; /* one past end of last free physical page */
/*
* Called very early in system boot to figure out how much physical
* RAM is available.
*/
void
ram_bootstrap(void)
{
size_t ramsize;
/* Get size of RAM. */
ramsize = mainbus_ramsize();
/*
* This is the same as the last physical address, as long as
* we have less than 512 megabytes of memory. If we had more,
* we wouldn't be able to access it all through kseg0 and
* everything would get a lot more complicated. This is not a
* case we are going to worry about.
*/
if (ramsize > 512*1024*1024) {
ramsize = 512*1024*1024;
}
lastpaddr = ramsize;
/*
* Get first free virtual address from where start.S saved it.
* Convert to physical address.
*/
firstpaddr = firstfree - MIPS_KSEG0;
kprintf("%uk physical memory available\n",
(lastpaddr-firstpaddr)/1024);
}
/*
* This function is for allocating physical memory prior to VM
* initialization.
*
* The pages it hands back will not be reported to the VM system when
* the VM system calls ram_getsize(). If it's desired to free up these
* pages later on after bootup is complete, some mechanism for adding
* them to the VM system's page management must be implemented.
* Alternatively, one can do enough VM initialization early so that
* this function is never needed.
*
* Note: while the error return value of 0 is a legal physical address,
* it's not a legal *allocatable* physical address, because it's the
* page with the exception handlers on it.
*
* This function should not be called once the VM system is initialized,
* so it is not synchronized.
*/
paddr_t
ram_stealmem(unsigned long npages)
{
size_t size;
paddr_t paddr;
size = npages * PAGE_SIZE;
if (firstpaddr + size > lastpaddr) {
return 0;
}
paddr = firstpaddr;
firstpaddr += size;
return paddr;
}
/*
* This function is intended to be called by the VM system when it
* initializes in order to find out what memory it has available to
* manage. Physical memory begins at physical address 0 and ends with
* the address returned by this function. We assume that physical
* memory is contiguous. This is not universally true, but is true on
* the MIPS platforms we intend to run on.
*
* lastpaddr is constant once set by ram_bootstrap(), so this function
* need not be synchronized.
*
* It is recommended, however, that this function be used only to
* initialize the VM system, after which the VM system should take
* charge of knowing what memory exists.
*/
paddr_t
ram_getsize(void)
{
return lastpaddr;
}
/*
* This function is intended to be called by the VM system when it
* initializes in order to find out what memory it has available to
* manage.
*
* It can only be called once, and once called ram_stealmem() will
* no longer work, as that would invalidate the result it returned
* and lead to multiple things using the same memory.
*
* This function should not be called once the VM system is initialized,
* so it is not synchronized.
*/
paddr_t
ram_getfirstfree(void)
{
paddr_t ret;
ret = firstpaddr;
firstpaddr = lastpaddr = 0;
return ret;
}

View File

@@ -0,0 +1,204 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <kern/mips/regdefs.h>
#include <mips/specialreg.h>
/*
* TLB handling for the MIPS-161.
*
* The MIPS-161 uses the simpler MIPS-1 (r2000/r3000) TLB rather
* than the paired-page TLB of later MIPS models.
*
* However, we handle MIPS32 pipeline hazards. If you want to run on
* a real MIPS-1, change the ssnops to plain nops and check where and
* how many you need in the matching processor docs.
*
* (ssnop means "superscalar nop"; it exists because the pipeline
* hazards require a fixed number of cycles, and a superscalar CPU can
* potentially issue arbitrarily many nops in one cycle.)
*/
.text
.set noreorder
.set mips32 /* so we can use ssnop */
/*
* tlb_random: use the "tlbwr" instruction to write a TLB entry
* into a (very pseudo-) random slot in the TLB.
*
* Pipeline hazard: must wait between setting entryhi/lo and
* doing the tlbwr. Use two cycles; some processors may vary.
*/
.globl tlb_random
.type tlb_random,@function
.ent tlb_random
tlb_random:
mtc0 a0, c0_entryhi /* store the passed entry into the */
mtc0 a1, c0_entrylo /* tlb entry registers */
ssnop /* wait for pipeline hazard */
ssnop
tlbwr /* do it */
j ra
nop
.end tlb_random
/*
* tlb_write: use the "tlbwi" instruction to write a TLB entry
* into a selected slot in the TLB.
*
* Pipeline hazard: must wait between setting entryhi/lo and
* doing the tlbwi. Use two cycles; some processors may vary.
*/
.text
.globl tlb_write
.type tlb_write,@function
.ent tlb_write
tlb_write:
mtc0 a0, c0_entryhi /* store the passed entry into the */
mtc0 a1, c0_entrylo /* tlb entry registers */
sll t0, a2, CIN_INDEXSHIFT /* shift the passed index into place */
mtc0 t0, c0_index /* store the shifted index into the index register */
ssnop /* wait for pipeline hazard */
ssnop
tlbwi /* do it */
j ra
nop
.end tlb_write
/*
* tlb_read: use the "tlbr" instruction to read a TLB entry
* from a selected slot in the TLB.
*
* Pipeline hazard: must wait between setting c0_index and
* doing the tlbr. Use two cycles; some processors may vary.
* Similarly, three more cycles before reading c0_entryhi/lo.
*/
.text
.globl tlb_read
.type tlb_read,@function
.ent tlb_read
tlb_read:
sll t0, a2, CIN_INDEXSHIFT /* shift the passed index into place */
mtc0 t0, c0_index /* store the shifted index into the index register */
ssnop /* wait for pipeline hazard */
ssnop
tlbr /* do it */
ssnop /* wait for pipeline hazard */
ssnop
ssnop
mfc0 t0, c0_entryhi /* get the tlb entry out of the */
mfc0 t1, c0_entrylo /* tlb entry registers */
sw t0, 0(a0) /* store through the passed pointer */
j ra
sw t1, 0(a1) /* store (in delay slot) */
.end tlb_read
/*
* tlb_probe: use the "tlbp" instruction to find the index in the
* TLB of a TLB entry matching the relevant parts of the one supplied.
*
* Pipeline hazard: must wait between setting c0_entryhi/lo and
* doing the tlbp. Use two cycles; some processors may vary.
* Similarly, two more cycles before reading c0_index.
*/
.text
.globl tlb_probe
.type tlb_probe,@function
.ent tlb_probe
tlb_probe:
mtc0 a0, c0_entryhi /* store the passed entry into the */
mtc0 a1, c0_entrylo /* tlb entry registers */
ssnop /* wait for pipeline hazard */
ssnop
tlbp /* do it */
ssnop /* wait for pipeline hazard */
ssnop
mfc0 t0, c0_index /* fetch the index back in t0 */
/*
* If the high bit (CIN_P) of c0_index is set, the probe failed.
* The high bit is not set <--> c0_index (now in t0) >= 0.
*/
bgez t0, 1f /* did probe succeed? if so, skip forward */
nop /* delay slot */
addi v0, z0, -1 /* set return value to -1 to indicate failure */
j ra /* done */
nop /* delay slot */
1:
/* succeeded - get the index field from the index register value */
andi t1, t0, CIN_INDEX /* mask off the field */
j ra /* done */
sra v0, t1, CIN_INDEXSHIFT /* shift it (in delay slot) */
.end tlb_probe
/*
* tlb_reset
*
* Initialize the TLB. At processor startup, the TLB state is completely
* undefined. So be sure to avoid creating any duplicates. Also make sure
* that the initialization entries don't duplicate the INVALID entries
* defined in tlb.h. (This way you can write the invalid entries in
* without having to use tlbp to find out if they're going to cause dups.)
*
* This function is not defined in tlb.h because it's only called from
* start.S.
*
* Pipeline hazards are as above.
*/
.text
.globl tlb_reset
.type tlb_reset,@function
.ent tlb_reset
tlb_reset:
li t0, 0 /* t0 <- tlb index number (shifted) */
li t1, 0x81000000 /* t1 <- tlb reset vaddr */
1:
mtc0 $0, c0_entrylo /* set up proposed tlb entry for reset */
mtc0 t1, c0_entryhi
ssnop /* wait for pipeline hazard */
ssnop
tlbp /* check if it already exists */
ssnop /* wait for pipeline hazard */
ssnop
mfc0 t2, c0_index
bgez t2, 1b /* if it does, loop back */
addiu t1, t1, 0x1000 /* next vaddr (in delay slot) */
mtc0 t0, c0_index /* doesn't exist, set index to write to */
ssnop /* wait for pipeline hazard */
ssnop
addiu t0, t0, 0x100 /* next tlb index (shifted) */
bne t0, 0x4000, 1b /* if it's not the last tlb index, loop */
tlbwi /* write tlb entry (in delay slot) */
j ra /* done */
nop /* delay slot */
.end tlb_reset

View File

@@ -0,0 +1,34 @@
#
# Platform-dependent sources for System/161.
#
#
# locore
#
# Cache handling for the kind of MIPS we have
platform sys161 file arch/mips/locore/cache-mips161.S
# Exception handling (assembler entry points) for the kind of MIPS we have
platform sys161 file arch/mips/locore/exception-mips1.S
#
# VM
#
# TLB handling for the kind of MIPS we have
platform sys161 file arch/mips/vm/tlb-mips161.S
#
# Devices. We have LAMEbus.
#
platform sys161 file arch/sys161/dev/lamebus_machdep.c
include dev/lamebus/conf.lamebus
#
# Startup and initialization.
#
platform sys161 file arch/sys161/main/start.S

View File

@@ -0,0 +1,334 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <kern/unistd.h>
#include <lib.h>
#include <mips/specialreg.h>
#include <mips/trapframe.h>
#include <cpu.h>
#include <spl.h>
#include <clock.h>
#include <thread.h>
#include <current.h>
#include <membar.h>
#include <synch.h>
#include <mainbus.h>
#include <sys161/bus.h>
#include <lamebus/lamebus.h>
#include "autoconf.h"
/*
* CPU frequency used by the on-chip timer.
*
* Note that we really ought to measure the CPU frequency against the
* real-time clock instead of compiling it in like this.
*/
#define CPU_FREQUENCY 25000000 /* 25 MHz */
/*
* Access to the on-chip timer.
*
* The c0_count register increments on every cycle; when the value
* matches the c0_compare register, the timer interrupt line is
* asserted. Writing to c0_compare again clears the interrupt.
*/
static
void
mips_timer_set(uint32_t count)
{
/*
* $11 == c0_compare; we can't use the symbolic name inside
* the asm string.
*/
__asm volatile(
".set push;" /* save assembler mode */
".set mips32;" /* allow MIPS32 registers */
"mtc0 %0, $11;" /* do it */
".set pop" /* restore assembler mode */
:: "r" (count));
}
/*
* LAMEbus data for the system. (We have only one LAMEbus per system.)
* This does not need to be locked, because it's constant once
* initialized, and initialized before we start other threads or CPUs.
*/
static struct lamebus_softc *lamebus;
void
mainbus_bootstrap(void)
{
/* Interrupts should be off (and have been off since startup) */
KASSERT(curthread->t_curspl > 0);
/* Initialize the system LAMEbus data */
lamebus = lamebus_init();
/* Probe CPUs (should these be done as device attachments instead?) */
lamebus_find_cpus(lamebus);
/*
* Print the device name for the main bus.
*/
kprintf("lamebus0 (system main bus)\n");
/*
* Now we can take interrupts without croaking, so turn them on.
* Some device probes might require being able to get interrupts.
*/
spl0();
/*
* Now probe all the devices attached to the bus.
* (This amounts to all devices.)
*/
autoconf_lamebus(lamebus, 0);
/*
* Configure the MIPS on-chip timer to interrupt HZ times a second.
*/
mips_timer_set(CPU_FREQUENCY / HZ);
}
/*
* Start all secondary CPUs.
*/
void
mainbus_start_cpus(void)
{
lamebus_start_cpus(lamebus);
}
/*
* Function to generate the memory address (in the uncached segment)
* for the specified offset into the specified slot's region of the
* LAMEbus.
*/
void *
lamebus_map_area(struct lamebus_softc *bus, int slot, uint32_t offset)
{
uint32_t address;
(void)bus; // not needed
KASSERT(slot >= 0 && slot < LB_NSLOTS);
address = LB_BASEADDR + slot*LB_SLOT_SIZE + offset;
return (void *)address;
}
/*
* Read a 32-bit register from a LAMEbus device.
*/
uint32_t
lamebus_read_register(struct lamebus_softc *bus, int slot, uint32_t offset)
{
uint32_t *ptr;
ptr = lamebus_map_area(bus, slot, offset);
/*
* Make sure the load happens after anything the device has
* been doing.
*/
membar_load_load();
return *ptr;
}
/*
* Write a 32-bit register of a LAMEbus device.
*/
void
lamebus_write_register(struct lamebus_softc *bus, int slot,
uint32_t offset, uint32_t val)
{
uint32_t *ptr;
ptr = lamebus_map_area(bus, slot, offset);
*ptr = val;
/*
* Make sure the store happens before we do anything else to
* the device.
*/
membar_store_store();
}
/*
* Power off the system.
*/
void
mainbus_poweroff(void)
{
/*
*
* Note that lamebus_write_register() doesn't actually access
* the bus argument, so this will still work if we get here
* before the bus is initialized.
*/
lamebus_poweroff(lamebus);
}
/*
* Reboot the system.
*/
void
mainbus_reboot(void)
{
/*
* The MIPS doesn't appear to have any on-chip reset.
* LAMEbus doesn't have a reset control, so we just
* power off instead of rebooting. This would not be
* so great in a real system, but it's fine for what
* we're doing.
*/
kprintf("Cannot reboot - powering off instead, sorry.\n");
mainbus_poweroff();
}
/*
* Halt the system.
* On some systems, this would return to the boot monitor. But we don't
* have one.
*/
void
mainbus_halt(void)
{
cpu_halt();
}
/*
* Called to reset the system from panic().
*
* By the time we get here, the system may well be sufficiently hosed
* as to panic recursively if we do much of anything. So just power off.
* (We'd reboot, but System/161 doesn't do that.)
*/
void
mainbus_panic(void)
{
mainbus_poweroff();
}
/*
* Function to get the size of installed physical RAM from the LAMEbus
* controller.
*/
uint32_t
mainbus_ramsize(void)
{
uint32_t ramsize;
ramsize = lamebus_ramsize();
/*
* This is the same as the last physical address, as long as
* we have less than 508 megabytes of memory. The LAMEbus I/O
* area occupies the space between 508 megabytes and 512
* megabytes, so if we had more RAM than this it would have to
* be discontiguous. This is not a case we are going to worry
* about.
*/
if (ramsize > 508*1024*1024) {
ramsize = 508*1024*1024;
}
return ramsize;
}
/*
* Send IPI.
*/
void
mainbus_send_ipi(struct cpu *target)
{
lamebus_assert_ipi(lamebus, target);
}
/*
* Interrupt dispatcher.
*/
/* Wiring of LAMEbus interrupts to bits in the cause register */
#define LAMEBUS_IRQ_BIT 0x00000400 /* all system bus slots */
#define LAMEBUS_IPI_BIT 0x00000800 /* inter-processor interrupt */
#define MIPS_TIMER_BIT 0x00008000 /* on-chip timer */
void
mainbus_interrupt(struct trapframe *tf)
{
uint32_t cause;
bool seen = false;
/* interrupts should be off */
KASSERT(curthread->t_curspl > 0);
cause = tf->tf_cause;
if (cause & LAMEBUS_IRQ_BIT) {
lamebus_interrupt(lamebus);
seen = true;
}
if (cause & LAMEBUS_IPI_BIT) {
interprocessor_interrupt();
lamebus_clear_ipi(lamebus, curcpu);
seen = true;
}
if (cause & MIPS_TIMER_BIT) {
/* Reset the timer (this clears the interrupt) */
mips_timer_set(CPU_FREQUENCY / HZ);
/* and call hardclock */
hardclock();
seen = true;
}
if (!seen) {
if ((cause & CCA_IRQS) == 0) {
/*
* Don't panic here; this can happen if an
* interrupt line asserts (very) briefly and
* turns off again before we get as far as
* reading the cause register. This was
* actually seen... once.
*/
}
else {
/*
* But if we get an interrupt on an interrupt
* line that's not supposed to be wired up,
* complain.
*/
panic("Unknown interrupt; cause register is %08x\n",
cause);
}
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _SYS161_BUS_H_
#define _SYS161_BUS_H_
/*
* Generic bus interface file.
*
* The only bus on System/161 is LAMEbus.
* This would need to be a bit more complicated if that weren't the case.
*/
#include <machine/vm.h> /* for MIPS_KSEG1 */
#include <lamebus/lamebus.h> /* for LAMEbus definitions */
#define bus_write_register(bus, slot, offset, val) \
lamebus_write_register(bus, slot, offset, val)
#define bus_read_register(bus, slot, offset) \
lamebus_read_register(bus, slot, offset)
#define bus_map_area(bus, slot, offset) \
lamebus_map_area(bus, slot, offset)
/*
* Machine-dependent LAMEbus definitions
*/
/* Base address of the LAMEbus mapping area */
#define LB_BASEADDR (MIPS_KSEG1 + 0x1fe00000)
#endif /* _SYS161_BUS_H_ */

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _SYS161_MAXCPUS_H_
#define _SYS161_MAXCPUS_H_
/*
* For various reasons (see mips/cpu.c) it's desirable to have a
* fixed-size per-cpu array in the data segment. This is
* platform-dependent rather than processor-dependent because there's
* nothing about the processor that determines how many CPUs can
* exist; however, any real platform has *some* limit. For System/161,
* the limit is 32.
*/
#define MAXCPUS 32
#endif /* _SYS161_MAXCPUS_H_ */

View File

@@ -0,0 +1,335 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <kern/mips/regdefs.h>
#include <mips/specialreg.h>
.set noreorder
.text
.globl __start
.type __start,@function
.ent __start
__start:
/*
* Stack frame. We save the return address register, even though
* it contains nothing useful. This is for gdb's benefit when it
* comes disassembling. We also need 16 bytes for making a call,
* and we have to align to an 8-byte (64-bit) boundary, so the
* total frame size is 24.
*
* Note that the frame here must match the frame we set up below
* when we switch off the bootup stack. Otherwise, gdb gets very
* confused.
*/
.frame sp, 24, $0 /* 24-byte sp-relative frame; return addr on stack */
.mask 0x80000000, -4 /* register 31 (ra) saved at (sp+24)-4 */
addiu sp, sp, -24
sw ra, 20(sp)
/*
* The System/161 loader sets up a boot stack for the first
* processor at the top of physical memory, and passes us a single
* string argument. The string lives on the very top of the stack.
* We get its address in a0.
*
* The kernel loads at virtual address 0x80000200, which is
* physical address 0x00000200. The space immediately below this
* is reserved for the exception vector code.
*
* The symbol _end is generated by the linker. It's the address of
* the end of the kernel. It's not a variable; the *value* of the
* _end symbol itself is this address. In C you'd use "&_end".
*
* We set up the memory map like this:
*
* top of memory
* free memory
* P + 0x1000
* first thread's stack (1 page)
* P
* wasted space (< 1 page)
* copy of the boot string
* _end
* kernel
* 0x80000200
* exception handlers
* 0x80000000
*
* where P is the next whole page after copying the argument string.
*/
la s0, _end /* stash _end in a saved register */
move a1, a0 /* move bootstring to the second argument */
move a0, s0 /* make _end the first argument */
jal strcpy /* call strcpy(_end, bootstring) */
nop /* delay slot */
move a0, s0 /* make _end the first argument again */
jal strlen /* call strlen(_end) */
nop
add t0, s0, v0 /* add in the length of the string */
addi t0, t0, 1 /* and the null terminator */
addi t0, t0, 4095 /* round up to next page boundary */
li t1, 0xfffff000
and t0, t0, t1
addi t0, t0, 4096 /* add one page to hold the stack */
move sp, t0 /* start the kernel stack for the first thread here */
sw t0, firstfree /* remember the first free page for later */
/*
* At this point, s0 contains the boot argument string, and no other
* registers contain anything interesting (except the stack pointer).
*/
/*
* Now set up a stack frame on the real kernel stack: a dummy saved
* return address and four argument slots for making function calls,
* plus a wasted slot for alignment.
*
* (This needs to match the stack frame set up at the top of the
* function, or the debugger gets confused.)
*/
addiu sp, sp, -24
sw $0, 20(sp)
/*
* Now, copy the exception handler code onto the first page of memory.
*/
li a0, EXADDR_UTLB
la a1, mips_utlb_handler
la a2, mips_utlb_end
sub a2, a2, a1
jal memmove
nop
li a0, EXADDR_GENERAL
la a1, mips_general_handler
la a2, mips_general_end
sub a2, a2, a1
jal memmove
nop
/*
* Flush the instruction cache to make sure the above changes show
* through to instruction fetch.
*/
jal mips_flushicache
nop
/*
* Initialize the TLB.
*/
jal tlb_reset
nop
/*
* Load NULL into the register we use for curthread.
*/
li s7, 0
/*
* Set up the status register.
*
* The MIPS has six hardware interrupt lines and two software interrupts.
* These are individually maskable in the status register. However, we
* don't use this feature (for simplicity) - we only use the master
* interrupt enable/disable flag in bit 0. So enable all of those bits
* now and forget about them.
*
* The BEV bit in the status register, if set, causes the processor to
* jump to a different set of hardwired exception handling addresses.
* This is so that the kernel's exception handling code can be loaded
* into RAM and that the boot ROM's exception handling code can be ROM.
* This flag is normally set at boot time, and we need to be sure to
* clear it.
*
* The KUo/IEo/KUp/IEp/KUc/IEc bits should all start at zero.
*
* We also want all the other random control bits (mostly for cache
* stuff) set to zero.
*
* Thus, the actual value we write is CST_IRQMASK.
*/
li t0, CST_IRQMASK /* get value */
mtc0 t0, c0_status /* set status register */
/*
* Load the CPU number into the PTBASE field of the CONTEXT
* register. This is necessary to read from cpustacks[] and
* cputhreads[] on trap entry from user mode. See further
* discussions elsewhere.
*
* Because the boot CPU is CPU 0, we can just send 0.
*/
mtc0 $0, c0_context
/*
* Load the GP register. This is a MIPS ABI feature; the GP
* register points to an address in the middle of the data segment,
* so data can be accessed relative to GP using one instruction
* instead of the two it takes to set up a full 32-bit address.
*/
la gp, _gp
/*
* We're all set up!
* Fetch the copy of the bootstring as the argument, and call main.
*/
jal kmain
move a0, s0 /* in delay slot */
/*
* kmain shouldn't return. panic.
* Loop back just in case panic returns too.
*/
1:
la a0, panicstr
jal panic
nop /* delay slot */
j 1b
nop /* delay slot */
.end __start
.rdata
panicstr:
.asciz "kmain returned\n"
/*
* CPUs started after the boot CPU come here.
*/
.text
.globl cpu_start_secondary
.type cpu_start_secondary,@function
.ent cpu_start_secondary
cpu_start_secondary:
/*
* When we get here our stack points to the CRAM area of the bus
* controller per-CPU space. This means we can, with a bit of
* caution, call C functions, but nothing very deeply nesting.
* However, we don't need to.
*
* The a0 register contains the value that was put in the second
* word of the CRAM area, which is the (software) cpu number for
* indexing cpustacks[]. None of the other registers contain
* anything useful.
*/
/*
* Stack frame. We save the return address register, even though
* it contains nothing useful. This is for gdb's benefit when it
* comes disassembling. We also need 16 bytes for making a call,
* and 4 bytes for alignment, so the total frame size is 24.
*
* Note that the frame here must match the frame we set up below
* when we switch stacks. Otherwise, gdb gets very confused.
*/
.frame sp, 24, $0 /* 24-byte sp-relative frame; return addr on stack */
.mask 0x80000000, -4 /* register 31 (ra) saved at (sp+24)-4 */
addiu sp, sp, -24
sw ra, 20(sp)
/*
* Fetch the stack out of cpustacks[].
*/
lui t0, %hi(cpustacks) /* load upper half of cpustacks base addr */
sll v0, a0, 2 /* get byte index for array (multiply by 4) */
addu t0, t0, v0 /* add it in */
lw sp, %lo(cpustacks)(t0) /* get the stack pointer */
/*
* Now fetch curthread out of cputhreads[].
*/
lui t0, %hi(cputhreads) /* load upper half of cpustacks base addr */
sll v0, a0, 2 /* get byte index for array (multiply by 4) */
addu t0, t0, v0 /* add it in */
lw s7, %lo(cputhreads)(t0) /* load curthread register */
/*
* Initialize the TLB.
*/
jal tlb_reset
nop
/*
* Set up the status register, as described above.
*/
li t0, CST_IRQMASK /* get value */
mtc0 t0, c0_status /* set status register */
/*
* Load the CPU number into the PTBASE field of the CONTEXT
* register, as described above.
*/
sll v0, a0, CTX_PTBASESHIFT
mtc0 v0, c0_context
/*
* Initialize the on-chip timer interrupt.
*
* This should be set to CPU_FREQUENCY/HZ, but we don't have either
* of those values here, so we'll arbitrarily set it to 100,000. It
* will get reset to the right thing after it first fires.
*/
li v0, 100000
mtc0 v0, c0_compare
/*
* Load the GP register.
*/
la gp, _gp
/*
* Set up a stack frame. Store zero into the return address slot so
* we show as the top of the stack.
*/
addiu sp, sp, -24
sw z0, 20(sp)
/*
* Off to MI code. Pass the cpu number as the argument; it's already
* in the a0 register.
*/
j cpu_hatch
nop /* delay slot for jump */
.end cpu_start_secondary

32
kern/conf/DUMBVM Normal file
View File

@@ -0,0 +1,32 @@
# Kernel config file using dumbvm.
# This should be used until you have your own VM system.
include conf/conf.kern # get definitions of available options
debug # Compile with debug info.
#
# Device drivers for hardware.
#
device lamebus0 # System/161 main bus
device emu* at lamebus* # Emulator passthrough filesystem
device ltrace* at lamebus* # trace161 trace control device
device ltimer* at lamebus* # Timer device
device lrandom* at lamebus* # Random device
device lhd* at lamebus* # Disk device
device lser* at lamebus* # Serial port
#device lscreen* at lamebus* # Text screen (not supported yet)
#device lnet* at lamebus* # Network interface (not supported yet)
device beep0 at ltimer* # Abstract beep handler device
device con0 at lser* # Abstract console on serial port
#device con0 at lscreen* # Abstract console on screen (not supported)
device rtclock0 at ltimer* # Abstract realtime clock
device random0 at lrandom* # Abstract randomness device
#options net # Network stack (not supported)
options semfs # Semaphores for userland
options sfs # Always use the file system
#options netfs # You might write this as a project.
options dumbvm # Chewing gum and baling wire.

36
kern/conf/DUMBVM-OPT Normal file
View File

@@ -0,0 +1,36 @@
# Kernel config file using dumbvm.
# This should be used until you have your own VM system.
#
# This config builds with optimization for performance testing.
#
include conf/conf.kern # get definitions of available options
#debug # Optimizing compile (no debug).
options noasserts # Disable assertions.
#
# Device drivers for hardware.
#
device lamebus0 # System/161 main bus
device emu* at lamebus* # Emulator passthrough filesystem
device ltrace* at lamebus* # trace161 trace control device
device ltimer* at lamebus* # Timer device
device lrandom* at lamebus* # Random device
device lhd* at lamebus* # Disk device
device lser* at lamebus* # Serial port
#device lscreen* at lamebus* # Text screen (not supported yet)
#device lnet* at lamebus* # Network interface (not supported yet)
device beep0 at ltimer* # Abstract beep handler device
device con0 at lser* # Abstract console on serial port
#device con0 at lscreen* # Abstract console on screen (not supported)
device rtclock0 at ltimer* # Abstract realtime clock
device random0 at lrandom* # Abstract randomness device
#options net # Network stack (not supported)
options semfs # Semaphores for userland
options sfs # Always use the file system
#options netfs # You might write this as a project.
options dumbvm # Chewing gum and baling wire.

33
kern/conf/GENERIC Normal file
View File

@@ -0,0 +1,33 @@
# Kernel config file for an ordinary, generic kernel.
# This config file should be used once you start working on
# your own VM system.
include conf/conf.kern # get definitions of available options
debug # Compile with debug info.
#
# Device drivers for hardware.
#
device lamebus0 # System/161 main bus
device emu* at lamebus* # Emulator passthrough filesystem
device ltrace* at lamebus* # trace161 trace control device
device ltimer* at lamebus* # Timer device
device lrandom* at lamebus* # Random device
device lhd* at lamebus* # Disk device
device lser* at lamebus* # Serial port
#device lscreen* at lamebus* # Text screen (not supported yet)
#device lnet* at lamebus* # Network interface (not supported yet)
device beep0 at ltimer* # Abstract beep handler device
device con0 at lser* # Abstract console on serial port
#device con0 at lscreen* # Abstract console on screen (not supported)
device rtclock0 at ltimer* # Abstract realtime clock
device random0 at lrandom* # Abstract randomness device
#options net # Network stack (not supported)
options semfs # Semaphores for userland
options sfs # Always use the file system
#options netfs # You might write this as a project.
#options dumbvm # Use your own VM system now.

36
kern/conf/GENERIC-OPT Normal file
View File

@@ -0,0 +1,36 @@
# Kernel config file for an ordinary, generic kernel.
# This config file should be used once you start working on
# your own VM system.
#
# This config builds with optimization for performance testing.
include conf/conf.kern # get definitions of available options
#debug # Optimizing compile (no debug).
options noasserts # Disable assertions.
#
# Device drivers for hardware.
#
device lamebus0 # System/161 main bus
device emu* at lamebus* # Emulator passthrough filesystem
device ltrace* at lamebus* # trace161 trace control device
device ltimer* at lamebus* # Timer device
device lrandom* at lamebus* # Random device
device lhd* at lamebus* # Disk device
device lser* at lamebus* # Serial port
#device lscreen* at lamebus* # Text screen (not supported yet)
#device lnet* at lamebus* # Network interface (not supported yet)
device beep0 at ltimer* # Abstract beep handler device
device con0 at lser* # Abstract console on serial port
#device con0 at lscreen* # Abstract console on screen (not supported)
device rtclock0 at ltimer* # Abstract realtime clock
device random0 at lrandom* # Abstract randomness device
#options net # Network stack (not supported)
options semfs # Semaphores for userland
options sfs # Always use the file system
#options netfs # You might write this as a project.
#options dumbvm # Use your own VM system now.

440
kern/conf/conf.kern Normal file
View File

@@ -0,0 +1,440 @@
#
# Machine-independent kernel config definitions.
#
# The idea is that the files, options, and facilities in the system
# are declared by conf.kern and the various files it includes. Then a
# kernel config (such as ASST1, or GENERIC, or TEST, or whatever) is
# used to select options and facilities for a particular kernel build.
#
# To add new files to the system, you need to edit this file (or
# others like it) and rerun the config script.
#
# Note: when running the config script, be sure to be in the
# right directory (the same one this file is in) and run it as
# "./config", not just "config" - in the latter case you will
# probably get the host system's kernel config utility, which
# will likely make a mess and produce mysterious error messages.
#
# The documentation for the syntax of these files follows.
#
############################################################
#
# Kernel config file syntax:
#
# The syntax for including the system definition is:
#
# include conf.kern
#
# This should come first. This is because the system must be
# defined before you can do much else useful.
#
# You can also include other files using the same syntax.
#
#
# The syntax for turning on a kernel compile option is:
#
# options optname
#
# A previous "defoption" must have been seen first. See below
# for more information.
#
# The act of compiling with debug info is (has to be) handled
# specially, and is just "debug" without the "options".
#
#
# The syntax for turning on a device driver is:
#
# device foo%
# device foo% at bar%
#
# where the % is either a number or a star, which is treated as
# a wildcard. The first line enables a device foo that is not
# supposed to be "attached" to anything. The second line enables
# a device foo that is attached to a device bar. For more
# information about what this means, see below.
#
#
############################################################
#
# Kernel definition file syntax:
#
# Note: All source file names are relative to the top directory of the
# kernel source, that is, src/kern.
#
# The syntax for adding a regular source file is:
#
# [machine M | platform P] file sourcefile.c
#
# Such a file is always included automatically in every kernel
# built for machine M, or platform P, or all kernels.
#
#
# The syntax for defining optional source files is:
#
# defoption optname
# [machine M | platform P] optfile optname sourcefile.c
# [machine M | platform P] optofffile optname sourcefile.c
#
# "defoption" declares the name of a kernel option. These are
# then turned on by including "options optname" in a
# kernel config.
#
# Source files added with optfile are compiled in if the option
# specified is enabled. Source files added with optofffile are
# compiled in if the option specified is not enabled.
#
# Additionally, a file "opt-optname.h" is created in the compile
# directory, which defines a C preprocessor symbol OPT_OPTNAME.
# This symbol is #defined to either 0 or 1 in the logical way.
# Thus, you can have small bits of code that are enabled or
# disabled by particular options by writing constructs like
#
# #include "opt-foo.h"
# #if OPT_FOO
# code();
# #else
# other_code();
# #endif
#
# *** Be sure to use #if and not #ifdef - you want the value
# of the symbol.
# *** Be sure to remember to include the header file for the
# option - if you don't, cpp will silently assume it is 0,
# which can be quite frustrating.
#
# The defoption must be seen before any optional file
# declarations that use it.
#
#
# The syntax for defining device drivers is:
#
# defdevice devname sourcefile.c
# defattach devname% otherdevname% sourcefile.c
# pseudoattach devname%
#
# Declare a device driver and its "attachment(s)". (The device
# driver can then be selectively included or not included in any
# particular kernel by using the "device" statement in the
# kernel config file.)
#
# The specified source files are only compiled if the device
# is enabled.
#
# The % is either a specific number N, meaning "only the Nth
# such device can be attached this way", or a star (*), meaning
# "any such device can be attached this way".
#
# In OS/161, device drivers are conceptually organized into
# trees. This mimics the organization of real hardware, where
# several expansion cards are plugged into one bus and there
# might be several devices on each expansion card and so forth.
#
# There can be any number of these trees. However, devices at
# the root of each tree must be able to probe and "find"
# themselves completely on their own. This generally means that
# they are either all software with no hardware, or they are the
# system main bus which is located in a machine-dependent way.
#
# Software-only devices are known as "pseudo-devices". These
# are "attached" with the pseudoattach directive; functions
# of the form
#
# pseudoattach_devname
#
# are called from autoconf.c to create instances as requested.
# These calls are made from the function pseudoconfig(), which
# should be called from dev/init.c after hardware device
# initialization completes. The pseudoattach functions should
# perform all setup and initialization necessary. (No
# config_devname function will be called.)
#
# Devices with attachments are automatically probed and
# configured from code in autoconf.c. This file is generated
# by the config script. It contains functions called
# "autoconf_devname", for each device. These functions call
# other functions, which are supplied by device drivers,
# which have the following hardwired names:
#
# attach_devname1_to_devname2
#
# A "devname2" device has been found and configured;
# this function attempts to probe the devname2 for
# a "devname1" device. Returns NULL if nothing was
# found.
#
# config_devname
#
# A "devname" device has been found. This function
# can then perform initialization that's shared
# among all the possible things it can be attached
# to.
#
# The idea is that there can be multiple attachments for
# the same device to different underlying devices. In the
# real world this can be used to great effect when you have,
# for instance, the same ethernet chipset used on both PCI
# and ISA cards - the chipset behaves the same way in both
# cases, but the probe and attach logic is very different.
#
# The attach_foo_to_bar functions are put in the files
# specified with defattach; the config_foo function (and
# generally the rest of the driver for the foo device) is
# put in the file specified with defdevice.
#
# One selects particular attachments when including the device
# in the kernel. A top-level device with no attachments should
# be included with this syntax:
#
# device bar
#
# A pseudo-device should be included with this syntax:
#
# device bar0
#
# To make use of device foo, which can be found attached to
# device bar, one of the following syntaxes is used:
#
# device foo* at bar*
# device foo* at bar0
# device foo0 at bar*
# device foo0 at bar0
#
# depending on to what extent you want to configure only a
# specific device number.
#
# It sometimes matters what order things are handled in; probes
# occur more or less in the order things appear in the config,
# as constrained by the tree structure of the available devices.
#
# Note that OS/161 does not make extensive use of this
# functionality, and the device driver architecture outlined
# here is overkill for such a limited environment as System/161.
# However, it's similar to the way real systems are organized.
#
#
# The syntax for including other config/definition files is:
#
# include filename
#
# The filename is relative to the top of the kernel source tree.
#
# Thus,
# include conf/conf.foo includes src/kern/conf/conf.foo
#
#
############################################################
########################################
# #
# Generic machine-independent devices. #
# #
########################################
#
# These are abstract system services we expect the system hardware to
# provide: beeping, system console I/O, and time of day clock.
#
# These come before the archinclude so that the hardware device
# definitions, which are included from there, can define attachments
# for them.
#
defdevice beep dev/generic/beep.c
defdevice con dev/generic/console.c
defdevice rtclock dev/generic/rtclock.c
defdevice random dev/generic/random.c
########################################
# #
# Machine-dependent stuff #
# #
########################################
#
# Get the definitions for each machine and platform supported. The
# ones used will be selected by make at compile time based on the
# contents of the top-level defs.mk file.
#
# This will declare a bunch of machine-dependent source files and also
# declare all the hardware devices (since what sorts of hardware we
# expect to find is machine-dependent.)
#
include arch/mips/conf/conf.arch
include arch/sys161/conf/conf.arch
########################################
# #
# Support code #
# #
########################################
#
# Kernel utility code
#
file lib/array.c
file lib/bitmap.c
file lib/bswap.c
file lib/kgets.c
file lib/kprintf.c
file lib/misc.c
file lib/time.c
file lib/uio.c
defoption noasserts
#
# Standard C functions
#
# For most of these, we take the source files from our libc. Note
# that those files have to have been hacked a bit to support this.
#
file ../common/libc/printf/__printf.c
file ../common/libc/printf/snprintf.c
file ../common/libc/stdlib/atoi.c
file ../common/libc/string/bzero.c
file ../common/libc/string/memcpy.c
file ../common/libc/string/memmove.c
file ../common/libc/string/memset.c
file ../common/libc/string/strcat.c
file ../common/libc/string/strchr.c
file ../common/libc/string/strcmp.c
file ../common/libc/string/strcpy.c
file ../common/libc/string/strlen.c
file ../common/libc/string/strrchr.c
file ../common/libc/string/strtok_r.c
########################################
# #
# Core kernel source files #
# #
########################################
#
# Thread system
#
file thread/clock.c
file thread/spl.c
file thread/spinlock.c
file thread/synch.c
file thread/thread.c
file thread/threadlist.c
#
# Process system
#
file proc/proc.c
#
# Virtual memory system
# (you will probably want to add stuff here while doing the VM assignment)
#
file vm/kmalloc.c
optofffile dumbvm vm/addrspace.c
#
# Network
# (nothing here yet)
#
defoption net
#optfile net net/net.c
#
# VFS layer
#
file vfs/device.c
file vfs/vfscwd.c
file vfs/vfsfail.c
file vfs/vfslist.c
file vfs/vfslookup.c
file vfs/vfspath.c
file vfs/vnode.c
#
# VFS devices
#
file vfs/devnull.c
#
# System call layer
# (You will probably want to add stuff here while doing the basic system
# calls assignment.)
#
file syscall/loadelf.c
file syscall/runprogram.c
file syscall/time_syscalls.c
#
# Startup and initialization
#
file main/main.c
file main/menu.c
########################################
# #
# Filesystems #
# #
########################################
#
# semfs (fake filesystem providing userlevel semaphores)
#
defoption semfs
optfile semfs fs/semfs/semfs_fsops.c
optfile semfs fs/semfs/semfs_obj.c
optfile semfs fs/semfs/semfs_vnops.c
#
# sfs (the small/simple filesystem)
#
defoption sfs
optfile sfs fs/sfs/sfs_balloc.c
optfile sfs fs/sfs/sfs_bmap.c
optfile sfs fs/sfs/sfs_dir.c
optfile sfs fs/sfs/sfs_fsops.c
optfile sfs fs/sfs/sfs_inode.c
optfile sfs fs/sfs/sfs_io.c
optfile sfs fs/sfs/sfs_vnops.c
#
# netfs (the networked filesystem - you might write this as one assignment)
#
defoption netfs
#optfile netfs fs/netfs/netfs_fs.c # or whatever
#
# Note that "emufs" is completely contained in the "emu" device.
#
########################################
# #
# Test code #
# #
########################################
file test/arraytest.c
file test/bitmaptest.c
file test/threadlisttest.c
file test/threadtest.c
file test/tt3.c
file test/synchtest.c
file test/semunit.c
file test/kmalloctest.c
file test/fstest.c
optfile net test/nettest.c

1063
kern/conf/config Executable file

File diff suppressed because it is too large Load Diff

67
kern/conf/newvers.sh Executable file
View File

@@ -0,0 +1,67 @@
#!/bin/sh
#
# newvers.sh - increment build number in current directory (a build directory)
# and emit vers.c.
# The build number is kept in the file "version".
#
# Usage: newvers.sh CONFIGNAME
#
# Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
# The President and Fellows of Harvard College.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
if [ ! -f autoconf.c ]; then
#
# If there's no file autoconf.c, we are in the wrong place.
#
echo "$0: Not in a kernel build directory"
exit 1
fi
if [ "x$1" = x ]; then
echo "Usage: $0 CONFIGNAME"
exit 1
fi
CONFIG="$1"
#
# Get and increment the version number
#
VERS=`cat version 2>/dev/null || echo 0`
VERS=`expr $VERS + 1`
echo "$VERS" > version
#
# Write vers.c
#
echo '/* This file is automatically generated. Edits will be lost.*/' > vers.c
echo "const int buildversion = $VERS;" >> vers.c
echo 'const char buildconfig[] = "'"$CONFIG"'";' >> vers.c

71
kern/dev/generic/beep.c Normal file
View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <kern/errno.h>
#include <lib.h>
#include <generic/beep.h>
#include "autoconf.h"
/*
* Machine-independent generic beep "device".
*
* Basically, all we do is remember something that can be used for
* beeping, and provide the beep() function to the rest of the kernel.
*
* The kernel config mechanism can be used to explicitly choose which
* of the available beeping devices to use, if more than one is
* available.
*/
static struct beep_softc *the_beep = NULL;
int
config_beep(struct beep_softc *bs, int unit)
{
/* We use only the first beep device. */
if (unit!=0) {
return ENODEV;
}
KASSERT(the_beep==NULL);
the_beep = bs;
return 0;
}
void
beep(void)
{
if (the_beep!=NULL) {
the_beep->bs_beep(the_beep->bs_devdata);
}
else {
kprintf("beep: Warning: no beep device\n");
}
}

43
kern/dev/generic/beep.h Normal file
View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _GENERIC_BEEP_H_
#define _GENERIC_BEEP_H_
/*
* The device info for the generic MI beep device - a function
* to call and a context pointer for it.
*/
struct beep_softc {
void *bs_devdata;
void (*bs_beep)(void *devdata);
};
#endif /* _GENERIC_BEEP_H_ */

397
kern/dev/generic/console.c Normal file
View File

@@ -0,0 +1,397 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Machine (and hardware) independent console driver.
*
* We expose a simple interface to the rest of the kernel: "putch" to
* print a character, "getch" to read one.
*
* As long as the device we're connected to does, we allow printing in
* an interrupt handler or with interrupts off (by polling),
* transparently to the caller. Note that getch by polling is not
* supported, although such support could be added without undue
* difficulty.
*
* Note that nothing happens until we have a device to write to. A
* buffer of size DELAYBUFSIZE is used to hold output that is
* generated before this point. This means that (1) using kprintf for
* debugging problems that occur early in initialization is awkward,
* and (2) if the system crashes before we find a console, no output
* at all may appear.
*/
#include <types.h>
#include <kern/errno.h>
#include <lib.h>
#include <uio.h>
#include <cpu.h>
#include <thread.h>
#include <current.h>
#include <synch.h>
#include <generic/console.h>
#include <vfs.h>
#include <device.h>
#include "autoconf.h"
/*
* The console device.
*/
static struct con_softc *the_console = NULL;
/*
* Lock so user I/Os are atomic.
* We use two locks so readers waiting for input don't lock out writers.
*/
static struct lock *con_userlock_read = NULL;
static struct lock *con_userlock_write = NULL;
//////////////////////////////////////////////////
/*
* This is for accumulating characters printed before the
* console is set up. Upon console setup they are dumped
* to the actual console; thenceforth this space is unused.
*/
#define DELAYBUFSIZE 1024
static char delayed_outbuf[DELAYBUFSIZE];
static size_t delayed_outbuf_pos=0;
static
void
putch_delayed(int ch)
{
/*
* No synchronization needed: called only during system startup
* by main thread.
*/
KASSERT(delayed_outbuf_pos < sizeof(delayed_outbuf));
delayed_outbuf[delayed_outbuf_pos++] = ch;
}
static
void
flush_delay_buf(void)
{
size_t i;
for (i=0; i<delayed_outbuf_pos; i++) {
putch(delayed_outbuf[i]);
}
delayed_outbuf_pos = 0;
}
//////////////////////////////////////////////////
/*
* Print a character, using polling instead of interrupts to wait for
* I/O completion.
*/
static
void
putch_polled(struct con_softc *cs, int ch)
{
cs->cs_sendpolled(cs->cs_devdata, ch);
}
//////////////////////////////////////////////////
/*
* Print a character, using interrupts to wait for I/O completion.
*/
static
void
putch_intr(struct con_softc *cs, int ch)
{
P(cs->cs_wsem);
cs->cs_send(cs->cs_devdata, ch);
}
/*
* Read a character, using interrupts to wait for I/O completion.
*/
static
int
getch_intr(struct con_softc *cs)
{
unsigned char ret;
P(cs->cs_rsem);
ret = cs->cs_gotchars[cs->cs_gotchars_tail];
cs->cs_gotchars_tail =
(cs->cs_gotchars_tail + 1) % CONSOLE_INPUT_BUFFER_SIZE;
return ret;
}
/*
* Called from underlying device when a read-ready interrupt occurs.
*
* Note: if gotchars_head == gotchars_tail, the buffer is empty. Thus
* if gotchars_head+1 == gotchars_tail, the buffer is full. A slightly
* tidier way to implement this check (that avoids wasting a slot,
* too) would be with a second semaphore used with a nonblocking P,
* but we don't have that in OS/161.
*/
void
con_input(void *vcs, int ch)
{
struct con_softc *cs = vcs;
unsigned nexthead;
nexthead = (cs->cs_gotchars_head + 1) % CONSOLE_INPUT_BUFFER_SIZE;
if (nexthead == cs->cs_gotchars_tail) {
/* overflow; drop character */
return;
}
cs->cs_gotchars[cs->cs_gotchars_head] = ch;
cs->cs_gotchars_head = nexthead;
V(cs->cs_rsem);
}
/*
* Called from underlying device when a write-done interrupt occurs.
*/
void
con_start(void *vcs)
{
struct con_softc *cs = vcs;
V(cs->cs_wsem);
}
//////////////////////////////////////////////////
/*
* Exported interface.
*
* Warning: putch must work even in an interrupt handler or with
* interrupts disabled, and before the console is probed. getch need
* not, and does not.
*/
void
putch(int ch)
{
struct con_softc *cs = the_console;
if (cs==NULL) {
putch_delayed(ch);
}
else if (curthread->t_in_interrupt ||
curthread->t_curspl > 0 ||
curcpu->c_spinlocks > 0) {
putch_polled(cs, ch);
}
else {
putch_intr(cs, ch);
}
}
int
getch(void)
{
struct con_softc *cs = the_console;
KASSERT(cs != NULL);
KASSERT(!curthread->t_in_interrupt && curthread->t_iplhigh_count == 0);
return getch_intr(cs);
}
////////////////////////////////////////////////////////////
/*
* VFS interface functions
*/
static
int
con_eachopen(struct device *dev, int openflags)
{
(void)dev;
(void)openflags;
return 0;
}
static
int
con_io(struct device *dev, struct uio *uio)
{
int result;
char ch;
struct lock *lk;
(void)dev; // unused
if (uio->uio_rw==UIO_READ) {
lk = con_userlock_read;
}
else {
lk = con_userlock_write;
}
KASSERT(lk != NULL);
lock_acquire(lk);
while (uio->uio_resid > 0) {
if (uio->uio_rw==UIO_READ) {
ch = getch();
if (ch=='\r') {
ch = '\n';
}
result = uiomove(&ch, 1, uio);
if (result) {
lock_release(lk);
return result;
}
if (ch=='\n') {
break;
}
}
else {
result = uiomove(&ch, 1, uio);
if (result) {
lock_release(lk);
return result;
}
if (ch=='\n') {
putch('\r');
}
putch(ch);
}
}
lock_release(lk);
return 0;
}
static
int
con_ioctl(struct device *dev, int op, userptr_t data)
{
/* No ioctls. */
(void)dev;
(void)op;
(void)data;
return EINVAL;
}
static const struct device_ops console_devops = {
.devop_eachopen = con_eachopen,
.devop_io = con_io,
.devop_ioctl = con_ioctl,
};
static
int
attach_console_to_vfs(struct con_softc *cs)
{
struct device *dev;
int result;
dev = kmalloc(sizeof(*dev));
if (dev==NULL) {
return ENOMEM;
}
dev->d_ops = &console_devops;
dev->d_blocks = 0;
dev->d_blocksize = 1;
dev->d_data = cs;
result = vfs_adddev("con", dev, 0);
if (result) {
kfree(dev);
return result;
}
return 0;
}
////////////////////////////////////////////////////////////
/*
* Config routine called by autoconf.c after we are attached to something.
*/
int
config_con(struct con_softc *cs, int unit)
{
struct semaphore *rsem, *wsem;
struct lock *rlk, *wlk;
/*
* Only allow one system console.
* Further devices that could be the system console are ignored.
*
* Do not hardwire the console to be "con1" instead of "con0",
* or these asserts will go off.
*/
if (unit>0) {
KASSERT(the_console!=NULL);
return ENODEV;
}
KASSERT(the_console==NULL);
rsem = sem_create("console read", 0);
if (rsem == NULL) {
return ENOMEM;
}
wsem = sem_create("console write", 1);
if (wsem == NULL) {
sem_destroy(rsem);
return ENOMEM;
}
rlk = lock_create("console-lock-read");
if (rlk == NULL) {
sem_destroy(rsem);
sem_destroy(wsem);
return ENOMEM;
}
wlk = lock_create("console-lock-write");
if (wlk == NULL) {
lock_destroy(rlk);
sem_destroy(rsem);
sem_destroy(wsem);
return ENOMEM;
}
cs->cs_rsem = rsem;
cs->cs_wsem = wsem;
cs->cs_gotchars_head = 0;
cs->cs_gotchars_tail = 0;
the_console = cs;
con_userlock_read = rlk;
con_userlock_write = wlk;
flush_delay_buf();
return attach_console_to_vfs(cs);
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _GENERIC_CONSOLE_H_
#define _GENERIC_CONSOLE_H_
/*
* Device data for the hardware-independent system console.
*
* devdata, send, and sendpolled are provided by the underlying
* device, and are to be initialized by the attach routine.
*/
#define CONSOLE_INPUT_BUFFER_SIZE 32
struct con_softc {
/* initialized by attach routine */
void *cs_devdata;
void (*cs_send)(void *devdata, int ch);
void (*cs_sendpolled)(void *devdata, int ch);
/* initialized by config routine */
struct semaphore *cs_rsem;
struct semaphore *cs_wsem;
unsigned char cs_gotchars[CONSOLE_INPUT_BUFFER_SIZE];
unsigned cs_gotchars_head; /* next slot to put a char in */
unsigned cs_gotchars_tail; /* next slot to take a char out */
};
/*
* Functions called by lower-level drivers
*/
void con_input(/*struct con_softc*/ void *cs, int ch);
void con_start(/*struct con_softc*/ void *cs);
/*
* Functions called by higher-level code
*
* putch/getch - see <lib.h>
*/
#endif /* _GENERIC_CONSOLE_H_ */

158
kern/dev/generic/random.c Normal file
View File

@@ -0,0 +1,158 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <kern/errno.h>
#include <kern/fcntl.h>
#include <lib.h>
#include <uio.h>
#include <vfs.h>
#include <generic/random.h>
#include "autoconf.h"
/*
* Machine-independent generic randomness device.
*
* Remembers something that's a random source, and provides random()
* and randmax() to the rest of the kernel.
*
* The kernel config mechanism can be used to explicitly choose which
* of the available random sources to use, if more than one is
* available.
*/
static struct random_softc *the_random = NULL;
/*
* VFS device functions.
* open: allow reading only.
*/
static
int
randeachopen(struct device *dev, int openflags)
{
(void)dev;
if (openflags != O_RDONLY) {
return EIO;
}
return 0;
}
/*
* VFS I/O function. Hand off to implementation.
*/
static
int
randio(struct device *dev, struct uio *uio)
{
struct random_softc *rs = dev->d_data;
if (uio->uio_rw != UIO_READ) {
return EIO;
}
return rs->rs_read(rs->rs_devdata, uio);
}
/*
* VFS ioctl function.
*/
static
int
randioctl(struct device *dev, int op, userptr_t data)
{
/*
* We don't support any ioctls.
*/
(void)dev;
(void)op;
(void)data;
return EIOCTL;
}
static const struct device_ops random_devops = {
.devop_eachopen = randeachopen,
.devop_io = randio,
.devop_ioctl = randioctl,
};
/*
* Config function.
*/
int
config_random(struct random_softc *rs, int unit)
{
int result;
/* We use only the first random device. */
if (unit!=0) {
return ENODEV;
}
KASSERT(the_random==NULL);
the_random = rs;
rs->rs_dev.d_ops = &random_devops;
rs->rs_dev.d_blocks = 0;
rs->rs_dev.d_blocksize = 1;
rs->rs_dev.d_data = rs;
/* Add the VFS device structure to the VFS device list. */
result = vfs_adddev("random", &rs->rs_dev, 0);
if (result) {
return result;
}
return 0;
}
/*
* Random number functions exported to the rest of the kernel.
*/
uint32_t
random(void)
{
if (the_random==NULL) {
panic("No random device\n");
}
return the_random->rs_random(the_random->rs_devdata);
}
uint32_t
randmax(void)
{
if (the_random==NULL) {
panic("No random device\n");
}
return the_random->rs_randmax(the_random->rs_devdata);
}

46
kern/dev/generic/random.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _GENERIC_RANDOM_H_
#define _GENERIC_RANDOM_H_
#include <device.h>
struct uio;
struct random_softc {
/* Initialized by lower-level attach routine */
void *rs_devdata;
uint32_t (*rs_random)(void *devdata);
uint32_t (*rs_randmax)(void *devdata);
int (*rs_read)(void *devdata, struct uio *uio);
struct device rs_dev;
};
#endif /* _GENERIC_RANDOM_H_ */

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Machine-independent generic clock "device".
*
* Basically, all we do is remember something that can be used for
* handling requests for the current time, and provide the gettime()
* function to the rest of the kernel.
*
* The kernel config mechanism can be used to explicitly choose which
* of the available clocks to use, if more than one is available.
*
* The system will panic if gettime() is called and there is no clock.
*/
#include <types.h>
#include <kern/errno.h>
#include <lib.h>
#include <clock.h>
#include <generic/rtclock.h>
#include "autoconf.h"
static struct rtclock_softc *the_clock = NULL;
int
config_rtclock(struct rtclock_softc *rtc, int unit)
{
/* We use only the first clock device. */
if (unit!=0) {
return ENODEV;
}
KASSERT(the_clock==NULL);
the_clock = rtc;
return 0;
}
void
gettime(struct timespec *ts)
{
KASSERT(the_clock!=NULL);
the_clock->rtc_gettime(the_clock->rtc_devdata, ts);
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _GENERIC_RTCLOCK_H_
#define _GENERIC_RTCLOCK_H_
/*
* The device info for the generic MI clock device - a function
* to call and a context pointer for it.
*/
struct timespec;
struct rtclock_softc {
void *rtc_devdata;
void (*rtc_gettime)(void *devdata, struct timespec *);
};
#endif /* _GENERIC_RTCLOCK_H_ */

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Attachment code for having the generic beep device use the LAMEbus
* ltimer device for beeping.
*/
#include <types.h>
#include <lib.h>
#include <generic/beep.h>
#include <lamebus/ltimer.h>
#include "autoconf.h"
struct beep_softc *
attach_beep_to_ltimer(int beepno, struct ltimer_softc *ls)
{
struct beep_softc *bs = kmalloc(sizeof(struct beep_softc));
if (bs==NULL) {
return NULL;
}
(void)beepno; // unused
bs->bs_devdata = ls;
bs->bs_beep = ltimer_beep;
return bs;
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Attachment code for having the generic console device use the LAMEbus
* screen device.
*/
#include <types.h>
#include <lib.h>
#include <generic/console.h>
#include <lamebus/lscreen.h>
#include "autoconf.h"
struct con_softc *
attach_con_to_lscreen(int consno, struct lscreen_softc *ls)
{
struct con_softc *cs = kmalloc(sizeof(struct con_softc));
if (cs==NULL) {
return NULL;
}
cs->cs_devdata = ls;
cs->cs_send = lscreen_write;
cs->cs_sendpolled = lscreen_write;
ls->ls_devdata = cs;
ls->ls_start = con_start;
ls->ls_input = con_input;
return cs;
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Attachment code for having the generic console device use the LAMEbus
* serial device.
*/
#include <types.h>
#include <lib.h>
#include <generic/console.h>
#include <lamebus/lser.h>
#include "autoconf.h"
struct con_softc *
attach_con_to_lser(int consno, struct lser_softc *ls)
{
struct con_softc *cs = kmalloc(sizeof(struct con_softc));
if (cs==NULL) {
return NULL;
}
(void)consno; // unused
cs->cs_devdata = ls;
cs->cs_send = lser_write;
cs->cs_sendpolled = lser_writepolled;
ls->ls_devdata = cs;
ls->ls_start = con_start;
ls->ls_input = con_input;
return cs;
}

View File

@@ -0,0 +1,57 @@
#
# Kernel config definitions for LAMEbus devices.
#
# See conf/conf.kern for more information.
#
# System main bus.
defdevice lamebus dev/lamebus/lamebus.c
# Timer.
defdevice ltimer dev/lamebus/ltimer.c
defattach ltimer* lamebus* dev/lamebus/ltimer_att.c
# Random.
defdevice lrandom dev/lamebus/lrandom.c
defattach lrandom* lamebus* dev/lamebus/lrandom_att.c
# Disk.
defdevice lhd dev/lamebus/lhd.c
defattach lhd* lamebus* dev/lamebus/lhd_att.c
# Serial port.
defdevice lser dev/lamebus/lser.c
defattach lser* lamebus* dev/lamebus/lser_att.c
# Text screen.
defdevice lscreen dev/lamebus/lscreen.c
defattach lscreen* lamebus* dev/lamebus/lscreen_att.c
# Network interface.
defdevice lnet dev/lamebus/lnet.c
defattach lnet* lamebus* dev/lamebus/lnet_att.c
# Trace control device.
defdevice ltrace dev/lamebus/ltrace.c
defattach ltrace* lamebus* dev/lamebus/ltrace_att.c
# Emulator passthrough filesystem.
defdevice emu dev/lamebus/emu.c
defattach emu* lamebus* dev/lamebus/emu_att.c
#
# Attachments to generic interface devices
#
# Consoles.
defattach con0 lser* dev/lamebus/con_lser.c
defattach con0 lscreen* dev/lamebus/con_lscreen.c
# Beeper.
defattach beep* ltimer* dev/lamebus/beep_ltimer.c
# Clock.
defattach rtclock* ltimer* dev/lamebus/rtclock_ltimer.c
# Random.
defattach random0 lrandom* dev/lamebus/random_lrandom.c

1357
kern/dev/lamebus/emu.c Normal file

File diff suppressed because it is too large Load Diff

62
kern/dev/lamebus/emu.h Normal file
View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LAMEBUS_EMU_H_
#define _LAMEBUS_EMU_H_
#define EMU_MAXIO 16384
#define EMU_ROOTHANDLE 0
/*
* The per-device data used by the emufs device driver.
* (Note that this is only a small portion of its actual data;
* all the filesystem stuff goes elsewhere.
*/
struct emu_softc {
/* Initialized by lower-level attach code */
void *e_busdata;
uint32_t e_buspos;
int e_unit;
/* Initialized by config_emu() */
struct lock *e_lock;
struct semaphore *e_sem;
void *e_iobuf;
/* Written by the interrupt handler */
uint32_t e_result;
};
/* Functions called by lower-level drivers */
void emu_irq(/*struct emu_softc*/ void *);
#endif /* _LAMEBUS_EMU_H_ */

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Code for probe/attach of the emu device to lamebus.
*/
#include <types.h>
#include <lib.h>
#include <lamebus/lamebus.h>
#include <lamebus/emu.h>
#include "autoconf.h"
/* Lowest revision we support */
#define LOW_VERSION 1
struct emu_softc *
attach_emu_to_lamebus(int emuno, struct lamebus_softc *sc)
{
struct emu_softc *es;
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_EMUFS,
LOW_VERSION, NULL);
if (slot < 0) {
return NULL;
}
es = kmalloc(sizeof(struct emu_softc));
if (es==NULL) {
return NULL;
}
es->e_busdata = sc;
es->e_buspos = slot;
es->e_unit = emuno;
lamebus_mark(sc, slot);
lamebus_attach_interrupt(sc, slot, es, emu_irq);
return es;
}

665
kern/dev/lamebus/lamebus.c Normal file
View File

@@ -0,0 +1,665 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Machine-independent LAMEbus code.
*/
#include <types.h>
#include <lib.h>
#include <cpu.h>
#include <membar.h>
#include <spinlock.h>
#include <current.h>
#include <lamebus/lamebus.h>
/* Register offsets within each config region */
#define CFGREG_VID 0 /* Vendor ID */
#define CFGREG_DID 4 /* Device ID */
#define CFGREG_DRL 8 /* Device Revision Level */
/* LAMEbus controller private registers (offsets within its config region) */
#define CTLREG_RAMSZ 0x200
#define CTLREG_IRQS 0x204
#define CTLREG_PWR 0x208
#define CTLREG_IRQE 0x20c
#define CTLREG_CPUS 0x210
#define CTLREG_CPUE 0x214
#define CTLREG_SELF 0x218
/* LAMEbus CPU control registers (offsets within each per-cpu region) */
#define CTLCPU_CIRQE 0x000
#define CTLCPU_CIPI 0x004
#define CTLCPU_CRAM 0x300
/*
* Read a config register for the given slot.
*/
static
inline
uint32_t
read_cfg_register(struct lamebus_softc *lb, int slot, uint32_t offset)
{
/* Note that lb might be NULL on some platforms in some contexts. */
offset += LB_CONFIG_SIZE*slot;
return lamebus_read_register(lb, LB_CONTROLLER_SLOT, offset);
}
/*
* Write a config register for a given slot.
*/
static
inline
void
write_cfg_register(struct lamebus_softc *lb, int slot, uint32_t offset,
uint32_t val)
{
offset += LB_CONFIG_SIZE*slot;
lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val);
}
/*
* Read one of the bus controller's registers.
*/
static
inline
uint32_t
read_ctl_register(struct lamebus_softc *lb, uint32_t offset)
{
/* Note that lb might be NULL on some platforms in some contexts. */
return read_cfg_register(lb, LB_CONTROLLER_SLOT, offset);
}
/*
* Write one of the bus controller's registers.
*/
static
inline
void
write_ctl_register(struct lamebus_softc *lb, uint32_t offset, uint32_t val)
{
write_cfg_register(lb, LB_CONTROLLER_SLOT, offset, val);
}
/*
* Write one of the bus controller's CPU control registers.
*/
static
inline
void
write_ctlcpu_register(struct lamebus_softc *lb, unsigned hw_cpunum,
uint32_t offset, uint32_t val)
{
offset += LB_CTLCPU_OFFSET + hw_cpunum * LB_CTLCPU_SIZE;
lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val);
}
/*
* Find and create secondary CPUs.
*/
void
lamebus_find_cpus(struct lamebus_softc *lamebus)
{
uint32_t mainboard_vid, mainboard_did;
uint32_t cpumask, self, bit, val;
unsigned i, numcpus, bootcpu;
unsigned hwnum[32];
mainboard_vid = read_cfg_register(lamebus, LB_CONTROLLER_SLOT,
CFGREG_VID);
mainboard_did = read_cfg_register(lamebus, LB_CONTROLLER_SLOT,
CFGREG_DID);
if (mainboard_vid == LB_VENDOR_CS161 &&
mainboard_did == LBCS161_UPBUSCTL) {
/* Old uniprocessor mainboard; no cpu registers. */
lamebus->ls_uniprocessor = 1;
return;
}
cpumask = read_ctl_register(lamebus, CTLREG_CPUS);
self = read_ctl_register(lamebus, CTLREG_SELF);
numcpus = 0;
bootcpu = 0;
for (i=0; i<32; i++) {
bit = (uint32_t)1 << i;
if ((cpumask & bit) != 0) {
if (self & bit) {
bootcpu = numcpus;
curcpu->c_hardware_number = i;
}
hwnum[numcpus] = i;
numcpus++;
}
}
for (i=0; i<numcpus; i++) {
if (i != bootcpu) {
cpu_create(hwnum[i]);
}
}
/*
* By default, route all interrupts only to the boot cpu. We
* could be arbitrarily more elaborate, up to things like
* dynamic load balancing.
*/
for (i=0; i<numcpus; i++) {
if (i != bootcpu) {
val = 0;
}
else {
val = 0xffffffff;
}
write_ctlcpu_register(lamebus, hwnum[i], CTLCPU_CIRQE, val);
}
}
/*
* Start up secondary CPUs.
*
* The first word of the CRAM area is set to the entry point for new
* CPUs; the second to the (software) CPU number. Note that the logic
* here assumes the boot CPU is CPU 0 and the others are 1-N as
* created in the function above. This is fine if all CPUs are on
* LAMEbus; if in some environment there are other CPUs about as well
* this logic will have to be made more complex.
*/
void
lamebus_start_cpus(struct lamebus_softc *lamebus)
{
uint32_t cpumask, self, bit;
uint32_t ctlcpuoffset;
uint32_t *cram;
unsigned i;
unsigned cpunum;
if (lamebus->ls_uniprocessor) {
return;
}
cpumask = read_ctl_register(lamebus, CTLREG_CPUS);
self = read_ctl_register(lamebus, CTLREG_SELF);
/* Poke in the startup address. */
cpunum = 1;
for (i=0; i<32; i++) {
bit = (uint32_t)1 << i;
if ((cpumask & bit) != 0) {
if (self & bit) {
continue;
}
ctlcpuoffset = LB_CTLCPU_OFFSET + i * LB_CTLCPU_SIZE;
cram = lamebus_map_area(lamebus,
LB_CONTROLLER_SLOT,
ctlcpuoffset + CTLCPU_CRAM);
cram[0] = (uint32_t)cpu_start_secondary;
cram[1] = cpunum++;
}
}
/* Ensure all the above writes get flushed. */
membar_store_store();
/* Now, enable them all. */
write_ctl_register(lamebus, CTLREG_CPUE, cpumask);
}
/*
* Probe function.
*
* Given a LAMEbus, look for a device that's not already been marked
* in use, has the specified IDs, and has a device revision level at
* least as high as the minimum specified.
*
* Returns the slot number found (0-31) or -1 if nothing suitable was
* found.
*
* If VERSION_RET is not null, return the device version found. This
* allows drivers to blacklist specific versions or otherwise conduct
* more specific checks.
*/
int
lamebus_probe(struct lamebus_softc *sc,
uint32_t vendorid, uint32_t deviceid,
uint32_t lowver, uint32_t *version_ret)
{
int slot;
uint32_t val;
/*
* Because the slot information in sc is used when dispatching
* interrupts, disable interrupts while working with it.
*/
spinlock_acquire(&sc->ls_lock);
for (slot=0; slot<LB_NSLOTS; slot++) {
if (sc->ls_slotsinuse & (1<<slot)) {
/* Slot already in use; skip */
continue;
}
val = read_cfg_register(sc, slot, CFGREG_VID);
if (val!=vendorid) {
/* Wrong vendor id */
continue;
}
val = read_cfg_register(sc, slot, CFGREG_DID);
if (val != deviceid) {
/* Wrong device id */
continue;
}
val = read_cfg_register(sc, slot, CFGREG_DRL);
if (val < lowver) {
/* Unsupported device revision */
continue;
}
if (version_ret != NULL) {
*version_ret = val;
}
/* Found something */
spinlock_release(&sc->ls_lock);
return slot;
}
/* Found nothing */
spinlock_release(&sc->ls_lock);
return -1;
}
/*
* Mark that a slot is in use.
* This prevents the probe routine from returning the same device over
* and over again.
*/
void
lamebus_mark(struct lamebus_softc *sc, int slot)
{
uint32_t mask = ((uint32_t)1) << slot;
KASSERT(slot>=0 && slot < LB_NSLOTS);
spinlock_acquire(&sc->ls_lock);
if ((sc->ls_slotsinuse & mask)!=0) {
panic("lamebus_mark: slot %d already in use\n", slot);
}
sc->ls_slotsinuse |= mask;
spinlock_release(&sc->ls_lock);
}
/*
* Mark that a slot is no longer in use.
*/
void
lamebus_unmark(struct lamebus_softc *sc, int slot)
{
uint32_t mask = ((uint32_t)1) << slot;
KASSERT(slot>=0 && slot < LB_NSLOTS);
spinlock_acquire(&sc->ls_lock);
if ((sc->ls_slotsinuse & mask)==0) {
panic("lamebus_mark: slot %d not marked in use\n", slot);
}
sc->ls_slotsinuse &= ~mask;
spinlock_release(&sc->ls_lock);
}
/*
* Register a function (and a device context pointer) to be called
* when a particular slot signals an interrupt.
*/
void
lamebus_attach_interrupt(struct lamebus_softc *sc, int slot,
void *devdata,
void (*irqfunc)(void *devdata))
{
uint32_t mask = ((uint32_t)1) << slot;
KASSERT(slot>=0 && slot < LB_NSLOTS);
spinlock_acquire(&sc->ls_lock);
if ((sc->ls_slotsinuse & mask)==0) {
panic("lamebus_attach_interrupt: slot %d not marked in use\n",
slot);
}
KASSERT(sc->ls_devdata[slot]==NULL);
KASSERT(sc->ls_irqfuncs[slot]==NULL);
sc->ls_devdata[slot] = devdata;
sc->ls_irqfuncs[slot] = irqfunc;
spinlock_release(&sc->ls_lock);
}
/*
* Unregister a function that was being called when a particular slot
* signaled an interrupt.
*/
void
lamebus_detach_interrupt(struct lamebus_softc *sc, int slot)
{
uint32_t mask = ((uint32_t)1) << slot;
KASSERT(slot>=0 && slot < LB_NSLOTS);
spinlock_acquire(&sc->ls_lock);
if ((sc->ls_slotsinuse & mask)==0) {
panic("lamebus_detach_interrupt: slot %d not marked in use\n",
slot);
}
KASSERT(sc->ls_irqfuncs[slot]!=NULL);
sc->ls_devdata[slot] = NULL;
sc->ls_irqfuncs[slot] = NULL;
spinlock_release(&sc->ls_lock);
}
/*
* Mask/unmask an interrupt using the global IRQE register.
*/
void
lamebus_mask_interrupt(struct lamebus_softc *lamebus, int slot)
{
uint32_t bits, mask = ((uint32_t)1) << slot;
KASSERT(slot >= 0 && slot < LB_NSLOTS);
spinlock_acquire(&lamebus->ls_lock);
bits = read_ctl_register(lamebus, CTLREG_IRQE);
bits &= ~mask;
write_ctl_register(lamebus, CTLREG_IRQE, bits);
spinlock_release(&lamebus->ls_lock);
}
void
lamebus_unmask_interrupt(struct lamebus_softc *lamebus, int slot)
{
uint32_t bits, mask = ((uint32_t)1) << slot;
KASSERT(slot >= 0 && slot < LB_NSLOTS);
spinlock_acquire(&lamebus->ls_lock);
bits = read_ctl_register(lamebus, CTLREG_IRQE);
bits |= mask;
write_ctl_register(lamebus, CTLREG_IRQE, bits);
spinlock_release(&lamebus->ls_lock);
}
/*
* LAMEbus interrupt handling function. (Machine-independent!)
*/
void
lamebus_interrupt(struct lamebus_softc *lamebus)
{
/*
* Note that despite the fact that "spl" stands for "set
* priority level", we don't actually support interrupt
* priorities. When an interrupt happens, we look through the
* slots to find the first interrupting device and call its
* interrupt routine, no matter what that device is.
*
* Note that the entire LAMEbus uses only one on-cpu interrupt line.
* Thus, we do not use any on-cpu interrupt priority system either.
*/
int slot;
uint32_t mask;
uint32_t irqs;
void (*handler)(void *);
void *data;
/* For keeping track of how many bogus things happen in a row. */
static int duds = 0;
int duds_this_time = 0;
/* and we better have a valid bus instance. */
KASSERT(lamebus != NULL);
/* Lock the softc */
spinlock_acquire(&lamebus->ls_lock);
/*
* Read the LAMEbus controller register that tells us which
* slots are asserting an interrupt condition.
*/
irqs = read_ctl_register(lamebus, CTLREG_IRQS);
if (irqs == 0) {
/*
* Huh? None of them? Must be a glitch.
*/
kprintf("lamebus: stray interrupt on cpu %u\n",
curcpu->c_number);
duds++;
duds_this_time++;
/*
* We could just return now, but instead we'll
* continue ahead. Because irqs == 0, nothing in the
* loop will execute, and passing through it gets us
* to the code that checks how many duds we've
* seen. This is important, because we just might get
* a stray interrupt that latches itself on. If that
* happens, we're pretty much toast, but it's better
* to panic and hopefully reset the system than to
* loop forever printing "stray interrupt".
*/
}
/*
* Go through the bits in the value we got back to see which
* ones are set.
*/
for (mask=1, slot=0; slot<LB_NSLOTS; mask<<=1, slot++) {
if ((irqs & mask) == 0) {
/* Nope. */
continue;
}
/*
* This slot is signalling an interrupt.
*/
if ((lamebus->ls_slotsinuse & mask)==0) {
/*
* No device driver is using this slot.
*/
duds++;
duds_this_time++;
continue;
}
if (lamebus->ls_irqfuncs[slot]==NULL) {
/*
* The device driver hasn't installed an interrupt
* handler.
*/
duds++;
duds_this_time++;
continue;
}
/*
* Call the interrupt handler. Release the spinlock
* while we do so, in case other CPUs are handling
* interrupts on other devices.
*/
handler = lamebus->ls_irqfuncs[slot];
data = lamebus->ls_devdata[slot];
spinlock_release(&lamebus->ls_lock);
handler(data);
spinlock_acquire(&lamebus->ls_lock);
/*
* Reload the mask of pending IRQs - if we just called
* hardclock, we might not have come back to this
* context for some time, and it might have changed.
*/
irqs = read_ctl_register(lamebus, CTLREG_IRQS);
}
/*
* If we get interrupts for a slot with no driver or no
* interrupt handler, it's fairly serious. Because LAMEbus
* uses level-triggered interrupts, if we don't shut off the
* condition, we'll keep getting interrupted continuously and
* the system will make no progress. But we don't know how to
* do that if there's no driver or no interrupt handler.
*
* So, if we get too many dud interrupts, panic, since it's
* better to panic and reset than to hang.
*
* If we get through here without seeing any duds this time,
* the condition, whatever it was, has gone away. It might be
* some stupid device we don't have a driver for, or it might
* have been an electrical transient. In any case, warn and
* clear the dud count.
*/
if (duds_this_time == 0 && duds > 0) {
kprintf("lamebus: %d dud interrupts\n", duds);
duds = 0;
}
if (duds > 10000) {
panic("lamebus: too many (%d) dud interrupts\n", duds);
}
/* Unlock the softc */
spinlock_release(&lamebus->ls_lock);
}
/*
* Have the bus controller power the system off.
*/
void
lamebus_poweroff(struct lamebus_softc *lamebus)
{
/*
* Write 0 to the power register to shut the system off.
*/
cpu_irqoff();
write_ctl_register(lamebus, CTLREG_PWR, 0);
/* The power doesn't go off instantly... so halt the cpu. */
cpu_halt();
}
/*
* Ask the bus controller how much memory we have.
*/
uint32_t
lamebus_ramsize(void)
{
/*
* Note that this has to work before bus initialization.
* On machines where lamebus_read_register doesn't work
* before bus initialization, this function can't be used
* for initial RAM size lookup.
*/
return read_ctl_register(NULL, CTLREG_RAMSZ);
}
/*
* Turn on or off the interprocessor interrupt line for a given CPU.
*/
void
lamebus_assert_ipi(struct lamebus_softc *lamebus, struct cpu *target)
{
if (lamebus->ls_uniprocessor) {
return;
}
write_ctlcpu_register(lamebus, target->c_hardware_number,
CTLCPU_CIPI, 1);
}
void
lamebus_clear_ipi(struct lamebus_softc *lamebus, struct cpu *target)
{
if (lamebus->ls_uniprocessor) {
return;
}
write_ctlcpu_register(lamebus, target->c_hardware_number,
CTLCPU_CIPI, 0);
}
/*
* Initial setup.
* Should be called from mainbus_bootstrap().
*/
struct lamebus_softc *
lamebus_init(void)
{
struct lamebus_softc *lamebus;
int i;
/* Allocate space for lamebus data */
lamebus = kmalloc(sizeof(struct lamebus_softc));
if (lamebus==NULL) {
panic("lamebus_init: Out of memory\n");
}
spinlock_init(&lamebus->ls_lock);
/*
* Initialize the LAMEbus data structure.
*/
lamebus->ls_slotsinuse = 1 << LB_CONTROLLER_SLOT;
for (i=0; i<LB_NSLOTS; i++) {
lamebus->ls_devdata[i] = NULL;
lamebus->ls_irqfuncs[i] = NULL;
}
lamebus->ls_uniprocessor = 0;
return lamebus;
}

182
kern/dev/lamebus/lamebus.h Normal file
View File

@@ -0,0 +1,182 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LAMEBUS_H_
#define _LAMEBUS_H_
#include <cpu.h>
#include <spinlock.h>
/*
* Linear Always Mapped Extents
*
* Machine-independent definitions.
*/
/* Vendors */
#define LB_VENDOR_CS161 1
/* CS161 devices */
#define LBCS161_UPBUSCTL 1
#define LBCS161_TIMER 2
#define LBCS161_DISK 3
#define LBCS161_SERIAL 4
#define LBCS161_SCREEN 5
#define LBCS161_NET 6
#define LBCS161_EMUFS 7
#define LBCS161_TRACE 8
#define LBCS161_RANDOM 9
#define LBCS161_MPBUSCTL 10
/* LAMEbus controller always goes in slot 31 */
#define LB_CONTROLLER_SLOT 31
/* Number of slots */
#define LB_NSLOTS 32
/* LAMEbus controller per-slot config space */
#define LB_CONFIG_SIZE 1024
/* LAMEbus controller per-cpu control space */
#define LB_CTLCPU_SIZE 1024
/* LAMEbus controller slot offset to per-cpu control space */
#define LB_CTLCPU_OFFSET 32768
/* LAMEbus mapping size per slot */
#define LB_SLOT_SIZE 65536
/* Pointer to kind of function called on interrupt */
typedef void (*lb_irqfunc)(void *devdata);
/*
* Driver data
*/
struct lamebus_softc {
struct spinlock ls_lock;
/* Accessed from interrupts; synchronized with ls_lock */
uint32_t ls_slotsinuse;
void *ls_devdata[LB_NSLOTS];
lb_irqfunc ls_irqfuncs[LB_NSLOTS];
/* Read-only once set early in boot */
unsigned ls_uniprocessor;
};
/*
* Allocate and set up a lamebus_softc for the system.
*/
struct lamebus_softc *lamebus_init(void);
/*
* Search for and create cpu structures for the CPUs on the mainboard.
*/
void lamebus_find_cpus(struct lamebus_softc *lamebus);
/*
* Start up secondary CPUs.
*/
void lamebus_start_cpus(struct lamebus_softc *lamebus);
/*
* Look for a not-in-use slot containing a device whose vendor and device
* ids match those provided, and whose version is in the range between
* lowver and highver, inclusive.
*
* Returns a slot number (0-31) or -1 if no such device is found.
*/
int lamebus_probe(struct lamebus_softc *,
uint32_t vendorid, uint32_t deviceid,
uint32_t lowver, uint32_t *version_ret);
/*
* Mark a slot in-use (that is, has a device driver attached to it),
* or unmark it. It is a fatal error to mark a slot that is already
* in use, or unmark a slot that is not in use.
*/
void lamebus_mark(struct lamebus_softc *, int slot);
void lamebus_unmark(struct lamebus_softc *, int slot);
/*
* Attach to an interrupt.
*/
void lamebus_attach_interrupt(struct lamebus_softc *, int slot,
void *devdata,
void (*irqfunc)(void *devdata));
/*
* Detach from interrupt.
*/
void lamebus_detach_interrupt(struct lamebus_softc *, int slot);
/*
* Mask/unmask an interrupt.
*/
void lamebus_mask_interrupt(struct lamebus_softc *, int slot);
void lamebus_unmask_interrupt(struct lamebus_softc *, int slot);
/*
* Function to call to handle a LAMEbus interrupt.
*/
void lamebus_interrupt(struct lamebus_softc *);
/*
* Have the LAMEbus controller power the system off.
*/
void lamebus_poweroff(struct lamebus_softc *);
/*
* Ask the bus controller how much memory we have.
*/
size_t lamebus_ramsize(void);
/*
* Turn on or off the inter-processor interrupt line to a CPU.
*/
void lamebus_assert_ipi(struct lamebus_softc *, struct cpu *targetcpu);
void lamebus_clear_ipi(struct lamebus_softc *, struct cpu *targetcpu);
/*
* Read/write 32-bit register at offset OFFSET within slot SLOT.
* (Machine dependent.)
*/
uint32_t lamebus_read_register(struct lamebus_softc *, int slot,
uint32_t offset);
void lamebus_write_register(struct lamebus_softc *, int slot,
uint32_t offset, uint32_t val);
/*
* Map a buffer that starts at offset OFFSET within slot SLOT.
*/
void *lamebus_map_area(struct lamebus_softc *, int slot,
uint32_t offset);
#endif /* _LAMEBUS_H_ */

308
kern/dev/lamebus/lhd.c Normal file
View File

@@ -0,0 +1,308 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* LAMEbus hard disk (lhd) driver.
*/
#include <types.h>
#include <kern/errno.h>
#include <lib.h>
#include <uio.h>
#include <membar.h>
#include <synch.h>
#include <platform/bus.h>
#include <vfs.h>
#include <lamebus/lhd.h>
#include "autoconf.h"
/* Registers (offsets within slot) */
#define LHD_REG_NSECT 0 /* Number of sectors */
#define LHD_REG_STAT 4 /* Status */
#define LHD_REG_SECT 8 /* Sector for I/O */
#define LHD_REG_RPM 12 /* Disk rotation speed (revs per minute) */
/* Status codes */
#define LHD_IDLE 0 /* Device idle */
#define LHD_WORKING 1 /* Operation in progress */
#define LHD_OK 4 /* Operation succeeded */
#define LHD_INVSECT 12 /* Invalid sector requested */
#define LHD_MEDIA 20 /* Media error */
#define LHD_ISWRITE 2 /* OR with above: I/O is a write */
#define LHD_STATEMASK 0x1d /* mask for masking out LHD_ISWRITE */
/* Buffer (offset within slot) */
#define LHD_BUFFER 32768
/*
* Shortcut for reading a register.
*/
static
inline
uint32_t lhd_rdreg(struct lhd_softc *lh, uint32_t reg)
{
return bus_read_register(lh->lh_busdata, lh->lh_buspos, reg);
}
/*
* Shortcut for writing a register.
*/
static
inline
void lhd_wreg(struct lhd_softc *lh, uint32_t reg, uint32_t val)
{
bus_write_register(lh->lh_busdata, lh->lh_buspos, reg, val);
}
/*
* Convert a result code from the hardware to an errno value.
*/
static
int lhd_code_to_errno(struct lhd_softc *lh, int code)
{
switch (code & LHD_STATEMASK) {
case LHD_OK: return 0;
case LHD_INVSECT: return EINVAL;
case LHD_MEDIA: return EIO;
}
kprintf("lhd%d: Unknown result code %d\n", lh->lh_unit, code);
return EAGAIN;
}
/*
* Record that an I/O has completed: save the result and poke the
* completion semaphore.
*/
static
void
lhd_iodone(struct lhd_softc *lh, int err)
{
lh->lh_result = err;
V(lh->lh_done);
}
/*
* Interrupt handler for lhd.
* Read the status register; if an operation finished, clear the status
* register and report completion.
*/
void
lhd_irq(void *vlh)
{
struct lhd_softc *lh = vlh;
uint32_t val;
val = lhd_rdreg(lh, LHD_REG_STAT);
switch (val & LHD_STATEMASK) {
case LHD_IDLE:
case LHD_WORKING:
break;
case LHD_OK:
case LHD_INVSECT:
case LHD_MEDIA:
lhd_wreg(lh, LHD_REG_STAT, 0);
lhd_iodone(lh, lhd_code_to_errno(lh, val));
break;
}
}
/*
* Function called when we are open()'d.
*/
static
int
lhd_eachopen(struct device *d, int openflags)
{
/*
* Don't need to do anything.
*/
(void)d;
(void)openflags;
return 0;
}
/*
* Function for handling ioctls.
*/
static
int
lhd_ioctl(struct device *d, int op, userptr_t data)
{
/*
* We don't support any ioctls.
*/
(void)d;
(void)op;
(void)data;
return EIOCTL;
}
#if 0
/*
* Reset the device.
* This could be used, for instance, on timeout, if you implement suitable
* facilities.
*/
static
void
lhd_reset(struct lhd_softc *lh)
{
lhd_wreg(lh, LHD_REG_STAT, 0);
}
#endif
/*
* I/O function (for both reads and writes)
*/
static
int
lhd_io(struct device *d, struct uio *uio)
{
struct lhd_softc *lh = d->d_data;
uint32_t sector = uio->uio_offset / LHD_SECTSIZE;
uint32_t sectoff = uio->uio_offset % LHD_SECTSIZE;
uint32_t len = uio->uio_resid / LHD_SECTSIZE;
uint32_t lenoff = uio->uio_resid % LHD_SECTSIZE;
uint32_t i;
uint32_t statval = LHD_WORKING;
int result;
/* Don't allow I/O that isn't sector-aligned. */
if (sectoff != 0 || lenoff != 0) {
return EINVAL;
}
/* Don't allow I/O past the end of the disk. */
/* XXX this check can overflow */
if (sector+len > lh->lh_dev.d_blocks) {
return EINVAL;
}
/* Set up the value to write into the status register. */
if (uio->uio_rw==UIO_WRITE) {
statval |= LHD_ISWRITE;
}
/* Loop over all the sectors we were asked to do. */
for (i=0; i<len; i++) {
/* Wait until nobody else is using the device. */
P(lh->lh_clear);
/*
* Are we writing? If so, transfer the data to the
* on-card buffer.
*/
if (uio->uio_rw == UIO_WRITE) {
result = uiomove(lh->lh_buf, LHD_SECTSIZE, uio);
membar_store_store();
if (result) {
V(lh->lh_clear);
return result;
}
}
/* Tell it what sector we want... */
lhd_wreg(lh, LHD_REG_SECT, sector+i);
/* and start the operation. */
lhd_wreg(lh, LHD_REG_STAT, statval);
/* Now wait until the interrupt handler tells us we're done. */
P(lh->lh_done);
/* Get the result value saved by the interrupt handler. */
result = lh->lh_result;
/*
* Are we reading? If so, and if we succeeded,
* transfer the data out of the on-card buffer.
*/
if (result==0 && uio->uio_rw==UIO_READ) {
membar_load_load();
result = uiomove(lh->lh_buf, LHD_SECTSIZE, uio);
}
/* Tell another thread it's cleared to go ahead. */
V(lh->lh_clear);
/* If we failed, return the error. */
if (result) {
return result;
}
}
return 0;
}
static const struct device_ops lhd_devops = {
.devop_eachopen = lhd_eachopen,
.devop_io = lhd_io,
.devop_ioctl = lhd_ioctl,
};
/*
* Setup routine called by autoconf.c when an lhd is found.
*/
int
config_lhd(struct lhd_softc *lh, int lhdno)
{
char name[32];
/* Figure out what our name is. */
snprintf(name, sizeof(name), "lhd%d", lhdno);
/* Get a pointer to the on-chip buffer. */
lh->lh_buf = bus_map_area(lh->lh_busdata, lh->lh_buspos, LHD_BUFFER);
/* Create the semaphores. */
lh->lh_clear = sem_create("lhd-clear", 1);
if (lh->lh_clear == NULL) {
return ENOMEM;
}
lh->lh_done = sem_create("lhd-done", 0);
if (lh->lh_done == NULL) {
sem_destroy(lh->lh_clear);
lh->lh_clear = NULL;
return ENOMEM;
}
/* Set up the VFS device structure. */
lh->lh_dev.d_ops = &lhd_devops;
lh->lh_dev.d_blocks = bus_read_register(lh->lh_busdata, lh->lh_buspos,
LHD_REG_NSECT);
lh->lh_dev.d_blocksize = LHD_SECTSIZE;
lh->lh_dev.d_data = lh;
/* Add the VFS device structure to the VFS device list. */
return vfs_adddev(name, &lh->lh_dev, 1);
}

64
kern/dev/lamebus/lhd.h Normal file
View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LAMEBUS_LHD_H_
#define _LAMEBUS_LHD_H_
#include <device.h>
/*
* Our sector size
*/
#define LHD_SECTSIZE 512
/*
* Hardware device data associated with lhd (LAMEbus hard disk)
*/
struct lhd_softc {
/* Initialized by lower-level attach code */
void *lh_busdata; /* The bus we're on */
uint32_t lh_buspos; /* Our slot on that bus */
int lh_unit; /* What number lhd we are */
/*
* Initialized by config_lhd
*/
void *lh_buf; /* Pointer to on-card I/O buffer */
int lh_result; /* Result from I/O operation */
struct semaphore *lh_clear; /* Synchronization */
struct semaphore *lh_done;
struct device lh_dev; /* VFS device structure */
};
/* Functions called by lower-level drivers */
void lhd_irq(/*struct lhd_softc*/ void *); /* Interrupt handler */
#endif /* _LAMEBUS_LHD_H_ */

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Code for probe/attach of lhd to LAMEbus.
*/
#include <types.h>
#include <lib.h>
#include <lamebus/lamebus.h>
#include <lamebus/lhd.h>
#include "autoconf.h"
/* Lowest revision we support */
#define LOW_VERSION 2
struct lhd_softc *
attach_lhd_to_lamebus(int lhdno, struct lamebus_softc *sc)
{
struct lhd_softc *lh;
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_DISK,
LOW_VERSION, NULL);
if (slot < 0) {
/* None found */
return NULL;
}
lh = kmalloc(sizeof(struct lhd_softc));
if (lh==NULL) {
/* Out of memory */
return NULL;
}
/* Record what the lhd is attached to */
lh->lh_busdata = sc;
lh->lh_buspos = slot;
lh->lh_unit = lhdno;
/* Mark the slot in use and collect interrupts */
lamebus_mark(sc, slot);
lamebus_attach_interrupt(sc, slot, lh, lhd_irq);
return lh;
}

46
kern/dev/lamebus/lnet.c Normal file
View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <kern/errno.h>
#include <lib.h>
/*#include <lamebus/lnet.h>*/ /* not yet */
#include "autoconf.h"
int
config_lnet(struct lnet_softc *sc, int lnetno)
{
(void)sc;
kprintf("lnet%d: No network support in system\n", lnetno);
return ENODEV;
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <lib.h>
#include <lamebus/lamebus.h>
#include "autoconf.h"
/* Lowest revision we support */
#define LOW_VERSION 1
/* Highest revision we support */
#define HIGH_VERSION 1
struct lnet_softc *
attach_lnet_to_lamebus(int lnetno, struct lamebus_softc *sc)
{
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_NET,
LOW_VERSION, HIGH_VERSION);
if (slot < 0) {
return NULL;
}
kprintf("lnet%d: No network support in system\n", lnetno);
return NULL;
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Driver for LAMEbus random generator card
*/
#include <types.h>
#include <lib.h>
#include <uio.h>
#include <platform/bus.h>
#include <lamebus/lrandom.h>
#include "autoconf.h"
/* Registers (offsets within slot) */
#define LR_REG_RAND 0 /* random register */
/* Constants */
#define LR_RANDMAX 0xffffffff
int
config_lrandom(struct lrandom_softc *lr, int lrandomno)
{
(void)lrandomno;
(void)lr;
return 0;
}
uint32_t
lrandom_random(void *devdata)
{
struct lrandom_softc *lr = devdata;
return bus_read_register(lr->lr_bus, lr->lr_buspos, LR_REG_RAND);
}
uint32_t
lrandom_randmax(void *devdata)
{
(void)devdata;
return LR_RANDMAX;
}
int
lrandom_read(void *devdata, struct uio *uio)
{
struct lrandom_softc *lr = devdata;
uint32_t val;
int result;
while (uio->uio_resid > 0) {
val = bus_read_register(lr->lr_bus, lr->lr_buspos,
LR_REG_RAND);
result = uiomove(&val, sizeof(val), uio);
if (result) {
return result;
}
}
return 0;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LAMEBUS_LRANDOM_H_
#define _LAMEBUS_LRANDOM_H_
struct uio;
struct lrandom_softc {
/* Initialized by lower-level attach routine */
void *lr_bus;
uint32_t lr_buspos;
};
/* Functions called by higher-level drivers */
uint32_t lrandom_random(/*struct lrandom_softc*/ void *devdata);
uint32_t lrandom_randmax(/*struct lrandom_softc*/ void *devdata);
int lrandom_read(/*struct lrandom_softc*/ void *, struct uio *);
#endif /* _LAMEBUS_LRANDOM_H_ */

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <lib.h>
#include <lamebus/lamebus.h>
#include <lamebus/lrandom.h>
#include "autoconf.h"
/* Lowest revision we support */
#define LOW_VERSION 1
struct lrandom_softc *
attach_lrandom_to_lamebus(int lrandomno, struct lamebus_softc *sc)
{
struct lrandom_softc *lr;
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_RANDOM,
LOW_VERSION, NULL);
if (slot < 0) {
return NULL;
}
lr = kmalloc(sizeof(struct lrandom_softc));
if (lr==NULL) {
return NULL;
}
(void)lrandomno; // unused
lr->lr_bus = sc;
lr->lr_buspos = slot;
lamebus_mark(sc, slot);
return lr;
}

225
kern/dev/lamebus/lscreen.c Normal file
View File

@@ -0,0 +1,225 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Driver for full-screen console.
*
* As of this writing the full-screen console is not supported in
* System/161, so this driver is untested and probably broken.
*/
#include <types.h>
#include <lib.h>
#include <spinlock.h>
#include <platform/bus.h>
#include <lamebus/lscreen.h>
#include "autoconf.h"
/* Registers (offsets within slot) */
#define LSCR_REG_POSN 0 /* Cursor position */
#define LSCR_REG_SIZE 4 /* Display size */
#define LSCR_REG_CHAR 8 /* Character in */
#define LSCR_REG_RIRQ 12 /* Read interrupt status */
/* Bits in the IRQ registers */
#define LSCR_IRQ_ENABLE 1
#define LSCR_IRQ_ACTIVE 2
/* Offset within slot of screen buffer */
#define LSCR_SCREEN 32768
/* Convert a 32-bit X/Y pair to X and Y coordinates. */
static
inline
void
splitxy(uint32_t xy, unsigned *x, unsigned *y)
{
*x = xy >> 16;
*y = xy & 0xffff;
}
/* Convert X and Y coordinates to a single 32-bit value. */
static
inline
uint32_t
mergexy(unsigned x, unsigned y)
{
uint32_t val = x;
return (val << 16) | y;
}
////////////////////////////////////////////////////////////
/*
* Interrupt handler.
*/
void
lscreen_irq(void *vsc)
{
struct lscreen_softc *sc = vsc;
uint32_t ch, x;
spinlock_acquire(&sc->ls_lock);
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_RIRQ);
if (x & LSCR_IRQ_ACTIVE) {
ch = bus_read_register(sc->ls_busdata, sc->ls_buspos,
LSCR_REG_CHAR);
bus_write_register(sc->ls_busdata, sc->ls_buspos,
LSCR_REG_RIRQ, LSCR_IRQ_ENABLE);
spinlock_release(&sc->ls_lock);
if (sc->ls_input) {
sc->ls_input(sc->ls_devdata, ch);
}
}
else {
spinlock_release(&sc->ls_lock);
}
}
////////////////////////////////////////////////////////////
/*
* Handle a newline on the screen.
*/
static
void
lscreen_newline(struct lscreen_softc *sc)
{
if (sc->ls_cy >= sc->ls_height-1) {
/*
* Scroll
*/
memmove(sc->ls_screen, sc->ls_screen + sc->ls_width,
sc->ls_width * (sc->ls_height-1));
bzero(sc->ls_screen + sc->ls_width * (sc->ls_height-1),
sc->ls_width);
}
else {
sc->ls_cy++;
}
sc->ls_cx=0;
}
/*
* Handle a printable character being written to the screen.
*/
static
void
lscreen_char(struct lscreen_softc *sc, int ch)
{
if (sc->ls_cx >= sc->ls_width) {
lscreen_newline(sc);
}
sc->ls_screen[sc->ls_cy*sc->ls_width + sc->ls_cx] = ch;
sc->ls_cx++;
}
/*
* Send a character to the screen.
* This should probably know about backspace and tab.
*/
void
lscreen_write(void *vsc, int ch)
{
struct lscreen_softc *sc = vsc;
int ccx, ccy;
spinlock_acquire(&sc->ls_lock);
switch (ch) {
case '\n': lscreen_newline(sc); break;
default: lscreen_char(sc, ch); break;
}
/*
* ccx/ccy = corrected cursor position
* (The cursor marks the next space text will appear in. But
* at the very end of the line, it should not move off the edge.)
*/
ccx = sc->ls_cx;
ccy = sc->ls_cy;
if (ccx==sc->ls_width) {
ccx--;
}
/* Set the cursor position */
bus_write_register(sc->ls_busdata, sc->ls_buspos,
LSCR_REG_POSN, mergexy(ccx, ccy));
spinlock_release(&sc->ls_lock);
}
////////////////////////////////////////////////////////////
/*
* Setup routine called by autoconf.c when an lscreen is found.
*/
int
config_lscreen(struct lscreen_softc *sc, int lscreenno)
{
uint32_t val;
(void)lscreenno;
spinlock_init(&sc->ls_lock);
/*
* Enable interrupting.
*/
bus_write_register(sc->ls_busdata, sc->ls_buspos,
LSCR_REG_RIRQ, LSCR_IRQ_ENABLE);
/*
* Get screen size.
*/
val = bus_read_register(sc->ls_busdata, sc->ls_buspos,
LSCR_REG_SIZE);
splitxy(val, &sc->ls_width, &sc->ls_height);
/*
* Get cursor position.
*/
val = bus_read_register(sc->ls_busdata, sc->ls_buspos,
LSCR_REG_POSN);
splitxy(val, &sc->ls_cx, &sc->ls_cy);
/*
* Get a pointer to the memory-mapped screen area.
*/
sc->ls_screen = bus_map_area(sc->ls_busdata, sc->ls_buspos,
LSCR_SCREEN);
return 0;
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LAMEBUS_LSCREEN_H_
#define _LAMEBUS_LSCREEN_H_
/*
* Hardware device data for memory-mapped fullscreen text console.
*/
struct lscreen_softc {
/* Initialized by config function */
struct spinlock ls_lock; // protects data and device regs
unsigned ls_width, ls_height; // screen size
unsigned ls_cx, ls_cy; // cursor position
char *ls_screen; // memory-mapped screen buffer
/* Initialized by lower-level attachment function */
void *ls_busdata; // bus we're on
uint32_t ls_buspos; // position on that bus
/* Initialized by higher-level attachment function */
void *ls_devdata; // data and functions for
void (*ls_start)(void *devdata); // upper device (perhaps
void (*ls_input)(void *devdata, int ch); // console)
};
/* Functions called by lower-level drivers */
void lscreen_irq(/*struct lser_softc*/ void *sc); // interrupt handler
/* Functions called by higher-level drivers */
void lscreen_write(/*struct lser_softc*/ void *sc, int ch); // output function
#endif /* _LAMEBUS_LSCREEN_H_ */

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Code for probe/attach of lscreen to LAMEbus.
*/
#include <types.h>
#include <lib.h>
#include <lamebus/lamebus.h>
#include <lamebus/lscreen.h>
#include "autoconf.h"
/* Lowest revision we support */
#define LOW_VERSION 1
/* Highest revision we support */
#define HIGH_VERSION 1
struct lscreen_softc *
attach_lscreen_to_lamebus(int lscreenno, struct lamebus_softc *sc)
{
struct lscreen_softc *ls;
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_SCREEN,
LOW_VERSION, HIGH_VERSION);
if (slot < 0) {
/* Not found */
return NULL;
}
ls = kmalloc(sizeof(struct lscreen_softc));
if (ls==NULL) {
/* Out of memory */
return NULL;
}
/* Record what it's attached to */
ls->ls_busdata = sc;
ls->ls_buspos = slot;
/* Mark the slot in use and hook the interrupt */
lamebus_mark(sc, slot);
lamebus_attach_interrupt(sc, slot, ls, lscreen_irq);
return ls;
}

192
kern/dev/lamebus/lser.c Normal file
View File

@@ -0,0 +1,192 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <lib.h>
#include <spinlock.h>
#include <platform/bus.h>
#include <lamebus/lser.h>
#include "autoconf.h"
/* Registers (offsets within slot) */
#define LSER_REG_CHAR 0 /* Character in/out */
#define LSER_REG_WIRQ 4 /* Write interrupt status */
#define LSER_REG_RIRQ 8 /* Read interrupt status */
/* Bits in the IRQ registers */
#define LSER_IRQ_ENABLE 1
#define LSER_IRQ_ACTIVE 2
#define LSER_IRQ_FORCE 4
void
lser_irq(void *vsc)
{
struct lser_softc *sc = vsc;
uint32_t x;
bool clear_to_write = false;
bool got_a_read = false;
uint32_t ch = 0;
spinlock_acquire(&sc->ls_lock);
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ);
if (x & LSER_IRQ_ACTIVE) {
x = LSER_IRQ_ENABLE;
sc->ls_wbusy = 0;
clear_to_write = true;
bus_write_register(sc->ls_busdata, sc->ls_buspos,
LSER_REG_WIRQ, x);
}
x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_RIRQ);
if (x & LSER_IRQ_ACTIVE) {
x = LSER_IRQ_ENABLE;
ch = bus_read_register(sc->ls_busdata, sc->ls_buspos,
LSER_REG_CHAR);
got_a_read = true;
bus_write_register(sc->ls_busdata, sc->ls_buspos,
LSER_REG_RIRQ, x);
}
spinlock_release(&sc->ls_lock);
if (clear_to_write && sc->ls_start != NULL) {
sc->ls_start(sc->ls_devdata);
}
if (got_a_read && sc->ls_input != NULL) {
sc->ls_input(sc->ls_devdata, ch);
}
}
void
lser_write(void *vls, int ch)
{
struct lser_softc *ls = vls;
spinlock_acquire(&ls->ls_lock);
if (ls->ls_wbusy) {
/*
* We're not clear to write.
*
* This should not happen. It's the job of the driver
* attached to us to not write until we call
* ls->ls_start.
*
* (Note: if we're the console, the panic will go to
* lser_writepolled for printing, because we hold a
* spinlock and interrupts are off; it won't recurse.)
*/
panic("lser: Not clear to write\n");
}
ls->ls_wbusy = true;
bus_write_register(ls->ls_busdata, ls->ls_buspos, LSER_REG_CHAR, ch);
spinlock_release(&ls->ls_lock);
}
static
void
lser_poll_until_write(struct lser_softc *sc)
{
uint32_t val;
KASSERT(spinlock_do_i_hold(&sc->ls_lock));
do {
val = bus_read_register(sc->ls_busdata, sc->ls_buspos,
LSER_REG_WIRQ);
}
while ((val & LSER_IRQ_ACTIVE) == 0);
}
void
lser_writepolled(void *vsc, int ch)
{
struct lser_softc *sc = vsc;
bool irqpending;
spinlock_acquire(&sc->ls_lock);
if (sc->ls_wbusy) {
irqpending = true;
lser_poll_until_write(sc);
/* Clear the ready condition, but leave the IRQ asserted */
bus_write_register(sc->ls_busdata, sc->ls_buspos,
LSER_REG_WIRQ,
LSER_IRQ_FORCE|LSER_IRQ_ENABLE);
}
else {
irqpending = false;
/* Clear the interrupt enable bit */
bus_write_register(sc->ls_busdata, sc->ls_buspos,
LSER_REG_WIRQ, 0);
}
/* Send the character. */
bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_CHAR, ch);
/* Wait until it's done. */
lser_poll_until_write(sc);
/*
* If there wasn't already an IRQ pending, clear the ready
* condition and turn interruption back on. But if there was,
* leave the register alone, with the ready condition set (and
* the force bit still on); in due course we'll get to the
* interrupt handler and they'll be cleared.
*/
if (!irqpending) {
bus_write_register(sc->ls_busdata, sc->ls_buspos,
LSER_REG_WIRQ, LSER_IRQ_ENABLE);
}
spinlock_release(&sc->ls_lock);
}
int
config_lser(struct lser_softc *sc, int lserno)
{
(void)lserno;
/*
* Enable interrupting.
*/
spinlock_init(&sc->ls_lock);
sc->ls_wbusy = false;
bus_write_register(sc->ls_busdata, sc->ls_buspos,
LSER_REG_RIRQ, LSER_IRQ_ENABLE);
bus_write_register(sc->ls_busdata, sc->ls_buspos,
LSER_REG_WIRQ, LSER_IRQ_ENABLE);
return 0;
}

57
kern/dev/lamebus/lser.h Normal file
View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LAMEBUS_LSER_H_
#define _LAMEBUS_LSER_H_
#include <spinlock.h>
struct lser_softc {
/* Initialized by config function */
struct spinlock ls_lock; /* protects ls_wbusy and device regs */
volatile bool ls_wbusy; /* true if write in progress */
/* Initialized by lower-level attachment function */
void *ls_busdata;
uint32_t ls_buspos;
/* Initialized by higher-level attachment function */
void *ls_devdata;
void (*ls_start)(void *devdata);
void (*ls_input)(void *devdata, int ch);
};
/* Functions called by lower-level drivers */
void lser_irq(/*struct lser_softc*/ void *sc);
/* Functions called by higher-level drivers */
void lser_write(/*struct lser_softc*/ void *sc, int ch);
void lser_writepolled(/*struct lser_softc*/ void *sc, int ch);
#endif /* _LAMEBUS_LSER_H_ */

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <lib.h>
#include <lamebus/lamebus.h>
#include <lamebus/lser.h>
#include "autoconf.h"
/* Lowest revision we support */
#define LOW_VERSION 1
struct lser_softc *
attach_lser_to_lamebus(int lserno, struct lamebus_softc *sc)
{
struct lser_softc *ls;
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_SERIAL,
LOW_VERSION, NULL);
if (slot < 0) {
return NULL;
}
ls = kmalloc(sizeof(struct lser_softc));
if (ls==NULL) {
return NULL;
}
(void)lserno; // unused
ls->ls_busdata = sc;
ls->ls_buspos = slot;
lamebus_mark(sc, slot);
lamebus_attach_interrupt(sc, slot, ls, lser_irq);
return ls;
}

187
kern/dev/lamebus/ltimer.c Normal file
View File

@@ -0,0 +1,187 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Driver for LAMEbus clock/timer card
*/
#include <types.h>
#include <lib.h>
#include <spl.h>
#include <clock.h>
#include <platform/bus.h>
#include <lamebus/ltimer.h>
#include "autoconf.h"
/* Registers (offsets within slot) */
#define LT_REG_SEC 0 /* time of day: seconds */
#define LT_REG_NSEC 4 /* time of day: nanoseconds */
#define LT_REG_ROE 8 /* Restart On countdown-timer Expiry flag */
#define LT_REG_IRQ 12 /* Interrupt status register */
#define LT_REG_COUNT 16 /* Time for countdown timer (usec) */
#define LT_REG_SPKR 20 /* Beep control */
/* Granularity of countdown timer (usec) */
#define LT_GRANULARITY 1000000
static bool havetimerclock;
/*
* Setup routine called by autoconf stuff when an ltimer is found.
*/
int
config_ltimer(struct ltimer_softc *lt, int ltimerno)
{
/*
* Running on System/161 2.x, we always use the processor
* on-chip timer for hardclock and we don't need ltimer as
* hardclock.
*
* Ideally there should be code here that will use an ltimer
* for hardclock if nothing else is available; e.g. if we
* wanted to make OS/161 2.x run on System/161 1.x. However,
* that requires a good bit more infrastructure for handling
* timers than we have and it doesn't seem worthwhile.
*
* It would also require some hacking, because all CPUs need
* to receive timer interrupts. (Exercise: how would you make
* sure all CPUs receive exactly one timer interrupt? Remember
* that LAMEbus uses level-triggered interrupts, so the
* hardware interrupt line will cause repeated interrupts if
* it's not reset on the device; but if it's reset on the
* device before all CPUs manage to see it, those CPUs won't
* be interrupted at all.)
*
* Note that the beep and rtclock devices *do* attach to
* ltimer.
*/
(void)ltimerno;
lt->lt_hardclock = 0;
/*
* We do, however, use ltimer for the timer clock, since the
* on-chip timer can't do that.
*/
if (!havetimerclock) {
havetimerclock = true;
lt->lt_timerclock = 1;
/* Wire it to go off once every second. */
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_ROE, 1);
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_COUNT,
LT_GRANULARITY);
}
return 0;
}
/*
* Interrupt handler.
*/
void
ltimer_irq(void *vlt)
{
struct ltimer_softc *lt = vlt;
uint32_t val;
val = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_IRQ);
if (val) {
/*
* Only call hardclock if we're responsible for hardclock.
* (Any additional timer devices are unused.)
*/
if (lt->lt_hardclock) {
hardclock();
}
/*
* Likewise for timerclock.
*/
if (lt->lt_timerclock) {
timerclock();
}
}
}
/*
* The timer device will beep if you write to the beep register. It
* doesn't matter what value you write. This function is called if
* the beep device is attached to this timer.
*/
void
ltimer_beep(void *vlt)
{
struct ltimer_softc *lt = vlt;
bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_SPKR, 440);
}
/*
* The timer device also has a realtime clock on it.
* This function gets called if the rtclock device is attached
* to this timer.
*/
void
ltimer_gettime(void *vlt, struct timespec *ts)
{
struct ltimer_softc *lt = vlt;
uint32_t secs1, secs2;
int spl;
/*
* Read the seconds twice, on either side of the nanoseconds.
* If nsecs is small, use the *later* value of seconds, in case
* the nanoseconds turned over between the time we got the earlier
* value and the time we got nsecs.
*
* Note that the clock in the ltimer device is accurate down
* to a single processor cycle, so this might actually matter
* now and then.
*
* Do it with interrupts off on the current processor to avoid
* getting garbage if we get an interrupt among the register
* reads.
*/
spl = splhigh();
secs1 = bus_read_register(lt->lt_bus, lt->lt_buspos,
LT_REG_SEC);
ts->tv_nsec = bus_read_register(lt->lt_bus, lt->lt_buspos,
LT_REG_NSEC);
secs2 = bus_read_register(lt->lt_bus, lt->lt_buspos,
LT_REG_SEC);
splx(spl);
if (ts->tv_nsec < 5000000) {
ts->tv_sec = secs2;
}
else {
ts->tv_sec = secs1;
}
}

56
kern/dev/lamebus/ltimer.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LAMEBUS_LTIMER_H_
#define _LAMEBUS_LTIMER_H_
struct timespec;
/*
* Hardware device data for LAMEbus timer device
*/
struct ltimer_softc {
/* Initialized by config function */
int lt_hardclock; /* true if we should call hardclock() */
int lt_timerclock; /* true if we should call timerclock() */
/* Initialized by lower-level attach routine */
void *lt_bus; /* bus we're on */
uint32_t lt_buspos; /* position (slot) on that bus */
};
/* Functions called by lower-level drivers */
void ltimer_irq(/*struct ltimer_softc*/ void *lt); // interrupt handler
/* Functions called by higher-level devices */
void ltimer_beep(/*struct ltimer_softc*/ void *devdata); // for beep device
void ltimer_gettime(/*struct ltimer_softc*/ void *devdata,
struct timespec *ts); // for rtclock
#endif /* _LAMEBUS_LTIMER_H_ */

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Routine for probing/attaching ltimer to LAMEbus.
*/
#include <types.h>
#include <lib.h>
#include <lamebus/lamebus.h>
#include <lamebus/ltimer.h>
#include "autoconf.h"
/* Lowest revision we support */
#define LOW_VERSION 1
struct ltimer_softc *
attach_ltimer_to_lamebus(int ltimerno, struct lamebus_softc *sc)
{
struct ltimer_softc *lt;
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_TIMER,
LOW_VERSION, NULL);
if (slot < 0) {
/* No ltimer (or no additional ltimer) found */
return NULL;
}
lt = kmalloc(sizeof(struct ltimer_softc));
if (lt==NULL) {
/* out of memory */
return NULL;
}
(void)ltimerno; // unused
/* Record what bus it's on */
lt->lt_bus = sc;
lt->lt_buspos = slot;
/* Mark the slot in use and hook that slot's interrupt */
lamebus_mark(sc, slot);
lamebus_attach_interrupt(sc, slot, lt, ltimer_irq);
return lt;
}

116
kern/dev/lamebus/ltrace.c Normal file
View File

@@ -0,0 +1,116 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <lib.h>
#include <platform/bus.h>
#include <lamebus/ltrace.h>
#include "autoconf.h"
/* Registers (offsets within slot) */
#define LTRACE_REG_TRON 0 /* trace on */
#define LTRACE_REG_TROFF 4 /* trace off */
#define LTRACE_REG_DEBUG 8 /* debug code */
#define LTRACE_REG_DUMP 12 /* dump the system */
#define LTRACE_REG_STOP 16 /* stop for the debugger */
#define LTRACE_REG_PROFEN 20 /* turn profiling on/off */
#define LTRACE_REG_PROFCL 24 /* clear the profile */
static struct ltrace_softc *the_trace;
void
ltrace_on(uint32_t code)
{
if (the_trace != NULL) {
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
LTRACE_REG_TRON, code);
}
}
void
ltrace_off(uint32_t code)
{
if (the_trace != NULL) {
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
LTRACE_REG_TROFF, code);
}
}
void
ltrace_debug(uint32_t code)
{
if (the_trace != NULL) {
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
LTRACE_REG_DEBUG, code);
}
}
void
ltrace_dump(uint32_t code)
{
if (the_trace != NULL) {
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
LTRACE_REG_DUMP, code);
}
}
void
ltrace_stop(uint32_t code)
{
if (the_trace != NULL && the_trace->lt_canstop) {
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
LTRACE_REG_STOP, code);
}
}
void
ltrace_setprof(uint32_t onoff)
{
if (the_trace != NULL && the_trace->lt_canprof) {
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
LTRACE_REG_PROFEN, onoff);
}
}
void
ltrace_eraseprof(void)
{
if (the_trace != NULL && the_trace->lt_canprof) {
bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos,
LTRACE_REG_PROFCL, 1);
}
}
int
config_ltrace(struct ltrace_softc *sc, int ltraceno)
{
(void)ltraceno;
the_trace = sc;
return 0;
}

90
kern/dev/lamebus/ltrace.h Normal file
View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LAMEBUS_LTRACE_H_
#define _LAMEBUS_LTRACE_H_
struct ltrace_softc {
/* Initialized by lower-level attachment function */
void *lt_busdata;
uint32_t lt_buspos;
bool lt_canstop;
bool lt_canprof;
};
/*
* Functions provided for debug hacking:
* ltrace_on: turns on the trace161 tracing flag CODE.
* ltrace_off: turns off the trace161 tracing flag CODE.
* ltrace_debug: causes sys161/trace161 to print a message with CODE.
* ltrace_dump: causes trace161 to do a complete state dump, tagged CODE.
* ltrace_stop: causes sys161/trace161 to drop to the debugger.
* ltrace_setprof: turn on and off trace161 profile collection.
* ltrace_eraseprof: discard trace161 profile collected so far.
*
* The flags for ltrace_on/off are the characters used to control
* tracing on the trace161 command line. See the System/161 manual for
* more information.
*
* ltrace_debug is for printing simple indications that a certain
* piece of code has been reached, like one might use kprintf, except
* that it is less invasive than kprintf. Think of it as setting the
* value of a readout on the system's front panel. (In real life,
* since computers don't have front panels with blinking lights any
* more, people often use the speaker or the top left corner of the
* screen for this purpose.)
*
* ltrace_dump dumps the entire system state and is primarily intended
* for regression testing of System/161. It might or might not prove
* useful for debugging as well.
*
* Calling ltrace_stop behaves similarly to hardwiring a breakpoint
* instruction in your code, except that debuggers have trouble
* stepping past hardwired breakpoints. Currently the value of the
* code is ignored.
*
* ltrace_setprof can be used to dynamically turn profiling on and
* off, if trace161 is collecting a profile. (Otherwise it does
* nothing.) This can be used to e.g. profile only code that executes
* while holding a given lock.
*
* ltrace_eraseprof can be used to clear the accumulated profile
* data, if trace161 is collecting a profile. (Otherwise it does
* nothing.) This can be used to e.g. exclude bootup actions from your
* profile.
*/
void ltrace_on(uint32_t code);
void ltrace_off(uint32_t code);
void ltrace_debug(uint32_t code);
void ltrace_dump(uint32_t code);
void ltrace_stop(uint32_t code);
void ltrace_setprof(uint32_t onoff);
void ltrace_eraseprof(void);
#endif /* _LAMEBUS_LTRACE_H_ */

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <lib.h>
#include <lamebus/lamebus.h>
#include <lamebus/ltrace.h>
#include "autoconf.h"
/* Lowest revision we support */
#define LOW_VERSION 1
/* Revision that supports ltrace_stop() */
#define STOP_VERSION 2
/* Revision that supports ltrace_prof() */
#define PROF_VERSION 3
struct ltrace_softc *
attach_ltrace_to_lamebus(int ltraceno, struct lamebus_softc *sc)
{
struct ltrace_softc *lt;
uint32_t drl;
int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_TRACE,
LOW_VERSION, &drl);
if (slot < 0) {
return NULL;
}
lt = kmalloc(sizeof(struct ltrace_softc));
if (lt==NULL) {
return NULL;
}
(void)ltraceno; // unused
lt->lt_busdata = sc;
lt->lt_buspos = slot;
lt->lt_canstop = drl >= STOP_VERSION;
lt->lt_canprof = drl >= PROF_VERSION;
lamebus_mark(sc, slot);
return lt;
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Attachment code for having the generic random device use the LAMEbus
* random device.
*/
#include <types.h>
#include <lib.h>
#include <generic/random.h>
#include <lamebus/lrandom.h>
#include "autoconf.h"
struct random_softc *
attach_random_to_lrandom(int randomno, struct lrandom_softc *ls)
{
struct random_softc *rs = kmalloc(sizeof(struct random_softc));
if (rs==NULL) {
return NULL;
}
(void)randomno; // unused
rs->rs_devdata = ls;
rs->rs_random = lrandom_random;
rs->rs_randmax = lrandom_randmax;
rs->rs_read = lrandom_read;
return rs;
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Code for attaching the (generic) rtclock device to the LAMEbus ltimer.
*
* rtclock is a generic clock interface that gets its clock service from
* an actual hardware clock of some kind. (Theoretically it could also
* get its clock service from a clock maintained in software, as is the
* case on most systems. However, no such driver has been written yet.)
*
* ltimer can provide this clock service.
*/
#include <types.h>
#include <lib.h>
#include <generic/rtclock.h>
#include <lamebus/ltimer.h>
#include "autoconf.h"
struct rtclock_softc *
attach_rtclock_to_ltimer(int rtclockno, struct ltimer_softc *ls)
{
/*
* No need to probe; ltimer always has a clock.
* Just allocate the rtclock, set our fields, and return it.
*/
struct rtclock_softc *rtc = kmalloc(sizeof(struct rtclock_softc));
if (rtc==NULL) {
/* Out of memory */
return NULL;
}
(void)rtclockno; // unused
rtc->rtc_devdata = ls;
rtc->rtc_gettime = ltimer_gettime;
return rtc;
}

123
kern/fs/semfs/semfs.h Normal file
View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef SEMFS_H
#define SEMFS_H
#include <array.h>
#include <fs.h>
#include <vnode.h>
#ifndef SEMFS_INLINE
#define SEMFS_INLINE INLINE
#endif
/*
* Constants
*/
#define SEMFS_ROOTDIR 0xffffffffU /* semnum for root dir */
/*
* A user-facing semaphore.
*
* We don't use the kernel-level semaphore to implement it (although
* that would be tidy) because we'd have to violate its abstraction.
* XXX: or would we? review once all this is done.
*/
struct semfs_sem {
struct lock *sems_lock; /* Lock to protect count */
struct cv *sems_cv; /* CV to wait */
unsigned sems_count; /* Semaphore count */
bool sems_hasvnode; /* The vnode exists */
bool sems_linked; /* In the directory */
};
DECLARRAY(semfs_sem, SEMFS_INLINE);
/*
* Directory entry; name and reference to a semaphore.
*/
struct semfs_direntry {
char *semd_name; /* Name */
unsigned semd_semnum; /* Which semaphore */
};
DECLARRAY(semfs_direntry, SEMFS_INLINE);
/*
* Vnode. These are separate from the semaphore structures so they can
* come and go at the whim of VOP_RECLAIM. (It might seem tidier to
* ignore VOP_RECLAIM and destroy vnodes only when the underlying
* objects are removed; but it ends up being more complicated in
* practice. XXX: review after finishing)
*/
struct semfs_vnode {
struct vnode semv_absvn; /* Abstract vnode */
struct semfs *semv_semfs; /* Back-pointer to fs */
unsigned semv_semnum; /* Which semaphore */
};
/*
* The structure for the semaphore file system. Ordinarily there
* is only one of these.
*/
struct semfs {
struct fs semfs_absfs; /* Abstract fs object */
struct lock *semfs_tablelock; /* Lock for following */
struct vnodearray *semfs_vnodes; /* Currently extant vnodes */
struct semfs_semarray *semfs_sems; /* Semaphores */
struct lock *semfs_dirlock; /* Lock for following */
struct semfs_direntryarray *semfs_dents; /* The root directory */
};
/*
* Arrays
*/
DEFARRAY(semfs_sem, SEMFS_INLINE);
DEFARRAY(semfs_direntry, SEMFS_INLINE);
/*
* Functions.
*/
/* in semfs_obj.c */
struct semfs_sem *semfs_sem_create(const char *name);
int semfs_sem_insert(struct semfs *, struct semfs_sem *, unsigned *);
void semfs_sem_destroy(struct semfs_sem *);
struct semfs_direntry *semfs_direntry_create(const char *name, unsigned semno);
void semfs_direntry_destroy(struct semfs_direntry *);
/* in semfs_vnops.c */
int semfs_getvnode(struct semfs *, unsigned, struct vnode **ret);
#endif /* SEMFS_H */

226
kern/fs/semfs/semfs_fsops.c Normal file
View File

@@ -0,0 +1,226 @@
/*
* Copyright (c) 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <kern/errno.h>
#include <synch.h>
#include <vfs.h>
#include <fs.h>
#include <vnode.h>
#include "semfs.h"
////////////////////////////////////////////////////////////
// fs-level operations
/*
* Sync doesn't need to do anything.
*/
static
int
semfs_sync(struct fs *fs)
{
(void)fs;
return 0;
}
/*
* We have only one volume name and it's hardwired.
*/
static
const char *
semfs_getvolname(struct fs *fs)
{
(void)fs;
return "sem";
}
/*
* Get the root directory vnode.
*/
static
int
semfs_getroot(struct fs *fs, struct vnode **ret)
{
struct semfs *semfs = fs->fs_data;
struct vnode *vn;
int result;
result = semfs_getvnode(semfs, SEMFS_ROOTDIR, &vn);
if (result) {
kprintf("semfs: couldn't load root vnode: %s\n",
strerror(result));
return result;
}
*ret = vn;
return 0;
}
////////////////////////////////////////////////////////////
// mount and unmount logic
/*
* Destructor for struct semfs.
*/
static
void
semfs_destroy(struct semfs *semfs)
{
struct semfs_sem *sem;
struct semfs_direntry *dent;
unsigned i, num;
num = semfs_semarray_num(semfs->semfs_sems);
for (i=0; i<num; i++) {
sem = semfs_semarray_get(semfs->semfs_sems, i);
semfs_sem_destroy(sem);
}
semfs_semarray_setsize(semfs->semfs_sems, 0);
num = semfs_direntryarray_num(semfs->semfs_dents);
for (i=0; i<num; i++) {
dent = semfs_direntryarray_get(semfs->semfs_dents, i);
semfs_direntry_destroy(dent);
}
semfs_direntryarray_setsize(semfs->semfs_dents, 0);
semfs_direntryarray_destroy(semfs->semfs_dents);
lock_destroy(semfs->semfs_dirlock);
semfs_semarray_destroy(semfs->semfs_sems);
vnodearray_destroy(semfs->semfs_vnodes);
lock_destroy(semfs->semfs_tablelock);
kfree(semfs);
}
/*
* Unmount routine. XXX: Since semfs is attached at boot and can't be
* remounted, maybe unmounting it shouldn't be allowed.
*/
static
int
semfs_unmount(struct fs *fs)
{
struct semfs *semfs = fs->fs_data;
lock_acquire(semfs->semfs_tablelock);
if (vnodearray_num(semfs->semfs_vnodes) > 0) {
lock_release(semfs->semfs_tablelock);
return EBUSY;
}
lock_release(semfs->semfs_tablelock);
semfs_destroy(semfs);
return 0;
}
/*
* Operations table.
*/
static const struct fs_ops semfs_fsops = {
.fsop_sync = semfs_sync,
.fsop_getvolname = semfs_getvolname,
.fsop_getroot = semfs_getroot,
.fsop_unmount = semfs_unmount,
};
/*
* Constructor for struct semfs.
*/
static
struct semfs *
semfs_create(void)
{
struct semfs *semfs;
semfs = kmalloc(sizeof(*semfs));
if (semfs == NULL) {
goto fail_total;
}
semfs->semfs_tablelock = lock_create("semfs_table");
if (semfs->semfs_tablelock == NULL) {
goto fail_semfs;
}
semfs->semfs_vnodes = vnodearray_create();
if (semfs->semfs_vnodes == NULL) {
goto fail_tablelock;
}
semfs->semfs_sems = semfs_semarray_create();
if (semfs->semfs_sems == NULL) {
goto fail_vnodes;
}
semfs->semfs_dirlock = lock_create("semfs_dir");
if (semfs->semfs_dirlock == NULL) {
goto fail_sems;
}
semfs->semfs_dents = semfs_direntryarray_create();
if (semfs->semfs_dents == NULL) {
goto fail_dirlock;
}
semfs->semfs_absfs.fs_data = semfs;
semfs->semfs_absfs.fs_ops = &semfs_fsops;
return semfs;
fail_dirlock:
lock_destroy(semfs->semfs_dirlock);
fail_sems:
semfs_semarray_destroy(semfs->semfs_sems);
fail_vnodes:
vnodearray_destroy(semfs->semfs_vnodes);
fail_tablelock:
lock_destroy(semfs->semfs_tablelock);
fail_semfs:
kfree(semfs);
fail_total:
return NULL;
}
/*
* Create the semfs. There is only one semfs and it's attached as
* "sem:" during bootup.
*/
void
semfs_bootstrap(void)
{
struct semfs *semfs;
int result;
semfs = semfs_create();
if (semfs == NULL) {
panic("Out of memory creating semfs\n");
}
result = vfs_addfs("sem", &semfs->semfs_absfs);
if (result) {
panic("Attaching semfs: %s\n", strerror(result));
}
}

145
kern/fs/semfs/semfs_obj.c Normal file
View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <kern/errno.h>
#include <synch.h>
#define SEMFS_INLINE
#include "semfs.h"
////////////////////////////////////////////////////////////
// semfs_sem
/*
* Constructor for semfs_sem.
*/
struct semfs_sem *
semfs_sem_create(const char *name)
{
struct semfs_sem *sem;
char lockname[32];
char cvname[32];
snprintf(lockname, sizeof(lockname), "sem:l.%s", name);
snprintf(cvname, sizeof(cvname), "sem:%s", name);
sem = kmalloc(sizeof(*sem));
if (sem == NULL) {
goto fail_return;
}
sem->sems_lock = lock_create(lockname);
if (sem->sems_lock == NULL) {
goto fail_sem;
}
sem->sems_cv = cv_create(cvname);
if (sem->sems_cv == NULL) {
goto fail_lock;
}
sem->sems_count = 0;
sem->sems_hasvnode = false;
sem->sems_linked = false;
return sem;
fail_lock:
lock_destroy(sem->sems_lock);
fail_sem:
kfree(sem);
fail_return:
return NULL;
}
/*
* Destructor for semfs_sem.
*/
void
semfs_sem_destroy(struct semfs_sem *sem)
{
cv_destroy(sem->sems_cv);
lock_destroy(sem->sems_lock);
kfree(sem);
}
/*
* Helper to insert a semfs_sem into the semaphore table.
*/
int
semfs_sem_insert(struct semfs *semfs, struct semfs_sem *sem, unsigned *ret)
{
unsigned i, num;
KASSERT(lock_do_i_hold(semfs->semfs_tablelock));
num = semfs_semarray_num(semfs->semfs_sems);
if (num == SEMFS_ROOTDIR) {
/* Too many */
return ENOSPC;
}
for (i=0; i<num; i++) {
if (semfs_semarray_get(semfs->semfs_sems, i) == NULL) {
semfs_semarray_set(semfs->semfs_sems, i, sem);
*ret = i;
return 0;
}
}
return semfs_semarray_add(semfs->semfs_sems, sem, ret);
}
////////////////////////////////////////////////////////////
// semfs_direntry
/*
* Constructor for semfs_direntry.
*/
struct semfs_direntry *
semfs_direntry_create(const char *name, unsigned semnum)
{
struct semfs_direntry *dent;
dent = kmalloc(sizeof(*dent));
if (dent == NULL) {
return NULL;
}
dent->semd_name = kstrdup(name);
if (dent->semd_name == NULL) {
kfree(dent);
return NULL;
}
dent->semd_semnum = semnum;
return dent;
}
/*
* Destructor for semfs_direntry.
*/
void
semfs_direntry_destroy(struct semfs_direntry *dent)
{
kfree(dent->semd_name);
kfree(dent);
}

799
kern/fs/semfs/semfs_vnops.c Normal file
View File

@@ -0,0 +1,799 @@
/*
* Copyright (c) 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <types.h>
#include <kern/errno.h>
#include <kern/fcntl.h>
#include <stat.h>
#include <uio.h>
#include <synch.h>
#include <thread.h>
#include <proc.h>
#include <current.h>
#include <vfs.h>
#include <vnode.h>
#include "semfs.h"
////////////////////////////////////////////////////////////
// basic ops
static
int
semfs_eachopen(struct vnode *vn, int openflags)
{
struct semfs_vnode *semv = vn->vn_data;
if (semv->semv_semnum == SEMFS_ROOTDIR) {
if ((openflags & O_ACCMODE) != O_RDONLY) {
return EISDIR;
}
if (openflags & O_APPEND) {
return EISDIR;
}
}
return 0;
}
static
int
semfs_ioctl(struct vnode *vn, int op, userptr_t data)
{
(void)vn;
(void)op;
(void)data;
return EINVAL;
}
static
int
semfs_gettype(struct vnode *vn, mode_t *ret)
{
struct semfs_vnode *semv = vn->vn_data;
*ret = semv->semv_semnum == SEMFS_ROOTDIR ? S_IFDIR : S_IFREG;
return 0;
}
static
bool
semfs_isseekable(struct vnode *vn)
{
struct semfs_vnode *semv = vn->vn_data;
if (semv->semv_semnum != SEMFS_ROOTDIR) {
/* seeking a semaphore doesn't mean anything */
return false;
}
return true;
}
static
int
semfs_fsync(struct vnode *vn)
{
(void)vn;
return 0;
}
////////////////////////////////////////////////////////////
// semaphore ops
/*
* XXX fold these two together
*/
static
struct semfs_sem *
semfs_getsembynum(struct semfs *semfs, unsigned semnum)
{
struct semfs_sem *sem;
lock_acquire(semfs->semfs_tablelock);
sem = semfs_semarray_get(semfs->semfs_sems, semnum);
lock_release(semfs->semfs_tablelock);
return sem;
}
static
struct semfs_sem *
semfs_getsem(struct semfs_vnode *semv)
{
struct semfs *semfs = semv->semv_semfs;
return semfs_getsembynum(semfs, semv->semv_semnum);
}
/*
* Wakeup helper. We only need to wake up if there are sleepers, which
* should only be the case if the old count is 0; and we only
* potentially need to wake more than one sleeper if the new count
* will be more than 1.
*/
static
void
semfs_wakeup(struct semfs_sem *sem, unsigned newcount)
{
if (sem->sems_count > 0 || newcount == 0) {
return;
}
if (newcount == 1) {
cv_signal(sem->sems_cv, sem->sems_lock);
}
else {
cv_broadcast(sem->sems_cv, sem->sems_lock);
}
}
/*
* stat() for semaphore vnodes
*/
static
int
semfs_semstat(struct vnode *vn, struct stat *buf)
{
struct semfs_vnode *semv = vn->vn_data;
struct semfs_sem *sem;
sem = semfs_getsem(semv);
bzero(buf, sizeof(*buf));
lock_acquire(sem->sems_lock);
buf->st_size = sem->sems_count;
buf->st_nlink = sem->sems_linked ? 1 : 0;
lock_release(sem->sems_lock);
buf->st_mode = S_IFREG | 0666;
buf->st_blocks = 0;
buf->st_dev = 0;
buf->st_ino = semv->semv_semnum;
return 0;
}
/*
* Read. This is P(); decrease the count by the amount read.
* Don't actually bother to transfer any data.
*/
static
int
semfs_read(struct vnode *vn, struct uio *uio)
{
struct semfs_vnode *semv = vn->vn_data;
struct semfs_sem *sem;
size_t consume;
sem = semfs_getsem(semv);
lock_acquire(sem->sems_lock);
while (uio->uio_resid > 0) {
if (sem->sems_count > 0) {
consume = uio->uio_resid;
if (consume > sem->sems_count) {
consume = sem->sems_count;
}
DEBUG(DB_SEMFS, "semfs: sem%u: P, count %u -> %u\n",
semv->semv_semnum, sem->sems_count,
sem->sems_count - consume);
sem->sems_count -= consume;
/* don't bother advancing the uio data pointers */
uio->uio_offset += consume;
uio->uio_resid -= consume;
}
if (uio->uio_resid == 0) {
break;
}
if (sem->sems_count == 0) {
DEBUG(DB_SEMFS, "semfs: sem%u: blocking\n",
semv->semv_semnum);
cv_wait(sem->sems_cv, sem->sems_lock);
}
}
lock_release(sem->sems_lock);
return 0;
}
/*
* Write. This is V(); increase the count by the amount written.
* Don't actually bother to transfer any data.
*/
static
int
semfs_write(struct vnode *vn, struct uio *uio)
{
struct semfs_vnode *semv = vn->vn_data;
struct semfs_sem *sem;
unsigned newcount;
sem = semfs_getsem(semv);
lock_acquire(sem->sems_lock);
while (uio->uio_resid > 0) {
newcount = sem->sems_count + uio->uio_resid;
if (newcount < sem->sems_count) {
/* overflow */
lock_release(sem->sems_lock);
return EFBIG;
}
DEBUG(DB_SEMFS, "semfs: sem%u: V, count %u -> %u\n",
semv->semv_semnum, sem->sems_count, newcount);
semfs_wakeup(sem, newcount);
sem->sems_count = newcount;
uio->uio_offset += uio->uio_resid;
uio->uio_resid = 0;
}
lock_release(sem->sems_lock);
return 0;
}
/*
* Truncate. Set the count to the specified value.
*
* This is slightly cheesy but it allows open(..., O_TRUNC) to reset a
* semaphore as one would expect. Also it allows creating semaphores
* and then initializing their counts to values other than zero.
*/
static
int
semfs_truncate(struct vnode *vn, off_t len)
{
/* We should just use UINT_MAX but we don't have it in the kernel */
const unsigned max = (unsigned)-1;
struct semfs_vnode *semv = vn->vn_data;
struct semfs_sem *sem;
unsigned newcount;
if (len < 0) {
return EINVAL;
}
if (len > (off_t)max) {
return EFBIG;
}
newcount = len;
sem = semfs_getsem(semv);
lock_acquire(sem->sems_lock);
semfs_wakeup(sem, newcount);
sem->sems_count = newcount;
lock_release(sem->sems_lock);
return 0;
}
////////////////////////////////////////////////////////////
// directory ops
/*
* Directory read. Note that there's only one directory (the semfs
* root) that has all the semaphores in it.
*/
static
int
semfs_getdirentry(struct vnode *dirvn, struct uio *uio)
{
struct semfs_vnode *dirsemv = dirvn->vn_data;
struct semfs *semfs = dirsemv->semv_semfs;
struct semfs_direntry *dent;
unsigned num, pos;
int result;
KASSERT(uio->uio_offset >= 0);
pos = uio->uio_offset;
lock_acquire(semfs->semfs_dirlock);
num = semfs_direntryarray_num(semfs->semfs_dents);
if (pos >= num) {
/* EOF */
result = 0;
}
else {
dent = semfs_direntryarray_get(semfs->semfs_dents, pos);
result = uiomove(dent->semd_name, strlen(dent->semd_name),
uio);
}
lock_release(semfs->semfs_dirlock);
return result;
}
/*
* stat() for dirs
*/
static
int
semfs_dirstat(struct vnode *vn, struct stat *buf)
{
struct semfs_vnode *semv = vn->vn_data;
struct semfs *semfs = semv->semv_semfs;
bzero(buf, sizeof(*buf));
lock_acquire(semfs->semfs_dirlock);
buf->st_size = semfs_direntryarray_num(semfs->semfs_dents);
lock_release(semfs->semfs_dirlock);
buf->st_mode = S_IFDIR | 1777;
buf->st_nlink = 2;
buf->st_blocks = 0;
buf->st_dev = 0;
buf->st_ino = SEMFS_ROOTDIR;
return 0;
}
/*
* Backend for getcwd. Since we don't support subdirs, it's easy; send
* back the empty string.
*/
static
int
semfs_namefile(struct vnode *vn, struct uio *uio)
{
(void)vn;
(void)uio;
return 0;
}
/*
* Create a semaphore.
*/
static
int
semfs_creat(struct vnode *dirvn, const char *name, bool excl, mode_t mode,
struct vnode **resultvn)
{
struct semfs_vnode *dirsemv = dirvn->vn_data;
struct semfs *semfs = dirsemv->semv_semfs;
struct semfs_direntry *dent;
struct semfs_sem *sem;
unsigned i, num, empty, semnum;
int result;
(void)mode;
if (!strcmp(name, ".") || !strcmp(name, "..")) {
return EEXIST;
}
lock_acquire(semfs->semfs_dirlock);
num = semfs_direntryarray_num(semfs->semfs_dents);
empty = num;
for (i=0; i<num; i++) {
dent = semfs_direntryarray_get(semfs->semfs_dents, i);
if (dent == NULL) {
if (empty == num) {
empty = i;
}
continue;
}
if (!strcmp(dent->semd_name, name)) {
/* found */
if (excl) {
lock_release(semfs->semfs_dirlock);
return EEXIST;
}
result = semfs_getvnode(semfs, dent->semd_semnum,
resultvn);
lock_release(semfs->semfs_dirlock);
return result;
}
}
/* create it */
sem = semfs_sem_create(name);
if (sem == NULL) {
result = ENOMEM;
goto fail_unlock;
}
lock_acquire(semfs->semfs_tablelock);
result = semfs_sem_insert(semfs, sem, &semnum);
lock_release(semfs->semfs_tablelock);
if (result) {
goto fail_uncreate;
}
dent = semfs_direntry_create(name, semnum);
if (dent == NULL) {
goto fail_uninsert;
}
if (empty < num) {
semfs_direntryarray_set(semfs->semfs_dents, empty, dent);
}
else {
result = semfs_direntryarray_add(semfs->semfs_dents, dent,
&empty);
if (result) {
goto fail_undent;
}
}
result = semfs_getvnode(semfs, semnum, resultvn);
if (result) {
goto fail_undir;
}
sem->sems_linked = true;
lock_release(semfs->semfs_dirlock);
return 0;
fail_undir:
semfs_direntryarray_set(semfs->semfs_dents, empty, NULL);
fail_undent:
semfs_direntry_destroy(dent);
fail_uninsert:
lock_acquire(semfs->semfs_tablelock);
semfs_semarray_set(semfs->semfs_sems, semnum, NULL);
lock_release(semfs->semfs_tablelock);
fail_uncreate:
semfs_sem_destroy(sem);
fail_unlock:
lock_release(semfs->semfs_dirlock);
return result;
}
/*
* Unlink a semaphore. As with other files, it may not actually
* go away if it's currently open.
*/
static
int
semfs_remove(struct vnode *dirvn, const char *name)
{
struct semfs_vnode *dirsemv = dirvn->vn_data;
struct semfs *semfs = dirsemv->semv_semfs;
struct semfs_direntry *dent;
struct semfs_sem *sem;
unsigned i, num;
int result;
if (!strcmp(name, ".") || !strcmp(name, "..")) {
return EINVAL;
}
lock_acquire(semfs->semfs_dirlock);
num = semfs_direntryarray_num(semfs->semfs_dents);
for (i=0; i<num; i++) {
dent = semfs_direntryarray_get(semfs->semfs_dents, i);
if (dent == NULL) {
continue;
}
if (!strcmp(name, dent->semd_name)) {
/* found */
sem = semfs_getsembynum(semfs, dent->semd_semnum);
lock_acquire(sem->sems_lock);
KASSERT(sem->sems_linked);
sem->sems_linked = false;
if (sem->sems_hasvnode == false) {
lock_acquire(semfs->semfs_tablelock);
semfs_semarray_set(semfs->semfs_sems,
dent->semd_semnum, NULL);
lock_release(semfs->semfs_tablelock);
lock_release(sem->sems_lock);
semfs_sem_destroy(sem);
}
else {
lock_release(sem->sems_lock);
}
semfs_direntryarray_set(semfs->semfs_dents, i, NULL);
semfs_direntry_destroy(dent);
result = 0;
goto out;
}
}
result = ENOENT;
out:
lock_release(semfs->semfs_dirlock);
return result;
}
/*
* Lookup: get a semaphore by name.
*/
static
int
semfs_lookup(struct vnode *dirvn, char *path, struct vnode **resultvn)
{
struct semfs_vnode *dirsemv = dirvn->vn_data;
struct semfs *semfs = dirsemv->semv_semfs;
struct semfs_direntry *dent;
unsigned i, num;
int result;
if (!strcmp(path, ".") || !strcmp(path, "..")) {
VOP_INCREF(dirvn);
*resultvn = dirvn;
return 0;
}
lock_acquire(semfs->semfs_dirlock);
num = semfs_direntryarray_num(semfs->semfs_dents);
for (i=0; i<num; i++) {
dent = semfs_direntryarray_get(semfs->semfs_dents, i);
if (dent == NULL) {
continue;
}
if (!strcmp(path, dent->semd_name)) {
result = semfs_getvnode(semfs, dent->semd_semnum,
resultvn);
lock_release(semfs->semfs_dirlock);
return result;
}
}
lock_release(semfs->semfs_dirlock);
return ENOENT;
}
/*
* Lookparent: because we don't have subdirs, just return the root
* dir and copy the name.
*/
static
int
semfs_lookparent(struct vnode *dirvn, char *path,
struct vnode **resultdirvn, char *namebuf, size_t bufmax)
{
if (strlen(path)+1 > bufmax) {
return ENAMETOOLONG;
}
strcpy(namebuf, path);
VOP_INCREF(dirvn);
*resultdirvn = dirvn;
return 0;
}
////////////////////////////////////////////////////////////
// vnode lifecycle operations
/*
* Destructor for semfs_vnode.
*/
static
void
semfs_vnode_destroy(struct semfs_vnode *semv)
{
vnode_cleanup(&semv->semv_absvn);
kfree(semv);
}
/*
* Reclaim - drop a vnode that's no longer in use.
*/
static
int
semfs_reclaim(struct vnode *vn)
{
struct semfs_vnode *semv = vn->vn_data;
struct semfs *semfs = semv->semv_semfs;
struct vnode *vn2;
struct semfs_sem *sem;
unsigned i, num;
lock_acquire(semfs->semfs_tablelock);
/* vnode refcount is protected by the vnode's ->vn_countlock */
spinlock_acquire(&vn->vn_countlock);
if (vn->vn_refcount > 1) {
/* consume the reference VOP_DECREF passed us */
vn->vn_refcount--;
spinlock_release(&vn->vn_countlock);
lock_release(semfs->semfs_tablelock);
return EBUSY;
}
spinlock_release(&vn->vn_countlock);
/* remove from the table */
num = vnodearray_num(semfs->semfs_vnodes);
for (i=0; i<num; i++) {
vn2 = vnodearray_get(semfs->semfs_vnodes, i);
if (vn2 == vn) {
vnodearray_remove(semfs->semfs_vnodes, i);
break;
}
}
if (semv->semv_semnum != SEMFS_ROOTDIR) {
sem = semfs_semarray_get(semfs->semfs_sems, semv->semv_semnum);
KASSERT(sem->sems_hasvnode);
sem->sems_hasvnode = false;
if (sem->sems_linked == false) {
semfs_semarray_set(semfs->semfs_sems,
semv->semv_semnum, NULL);
semfs_sem_destroy(sem);
}
}
/* done with the table */
lock_release(semfs->semfs_tablelock);
/* destroy it */
semfs_vnode_destroy(semv);
return 0;
}
/*
* Vnode ops table for dirs.
*/
static const struct vnode_ops semfs_dirops = {
.vop_magic = VOP_MAGIC,
.vop_eachopen = semfs_eachopen,
.vop_reclaim = semfs_reclaim,
.vop_read = vopfail_uio_isdir,
.vop_readlink = vopfail_uio_isdir,
.vop_getdirentry = semfs_getdirentry,
.vop_write = vopfail_uio_isdir,
.vop_ioctl = semfs_ioctl,
.vop_stat = semfs_dirstat,
.vop_gettype = semfs_gettype,
.vop_isseekable = semfs_isseekable,
.vop_fsync = semfs_fsync,
.vop_mmap = vopfail_mmap_isdir,
.vop_truncate = vopfail_truncate_isdir,
.vop_namefile = semfs_namefile,
.vop_creat = semfs_creat,
.vop_symlink = vopfail_symlink_nosys,
.vop_mkdir = vopfail_mkdir_nosys,
.vop_link = vopfail_link_nosys,
.vop_remove = semfs_remove,
.vop_rmdir = vopfail_string_nosys,
.vop_rename = vopfail_rename_nosys,
.vop_lookup = semfs_lookup,
.vop_lookparent = semfs_lookparent,
};
/*
* Vnode ops table for semaphores (files).
*/
static const struct vnode_ops semfs_semops = {
.vop_magic = VOP_MAGIC,
.vop_eachopen = semfs_eachopen,
.vop_reclaim = semfs_reclaim,
.vop_read = semfs_read,
.vop_readlink = vopfail_uio_inval,
.vop_getdirentry = vopfail_uio_notdir,
.vop_write = semfs_write,
.vop_ioctl = semfs_ioctl,
.vop_stat = semfs_semstat,
.vop_gettype = semfs_gettype,
.vop_isseekable = semfs_isseekable,
.vop_fsync = semfs_fsync,
.vop_mmap = vopfail_mmap_perm,
.vop_truncate = semfs_truncate,
.vop_namefile = vopfail_uio_notdir,
.vop_creat = vopfail_creat_notdir,
.vop_symlink = vopfail_symlink_notdir,
.vop_mkdir = vopfail_mkdir_notdir,
.vop_link = vopfail_link_notdir,
.vop_remove = vopfail_string_notdir,
.vop_rmdir = vopfail_string_notdir,
.vop_rename = vopfail_rename_notdir,
.vop_lookup = vopfail_lookup_notdir,
.vop_lookparent = vopfail_lookparent_notdir,
};
/*
* Constructor for semfs vnodes.
*/
static
struct semfs_vnode *
semfs_vnode_create(struct semfs *semfs, unsigned semnum)
{
const struct vnode_ops *optable;
struct semfs_vnode *semv;
int result;
if (semnum == SEMFS_ROOTDIR) {
optable = &semfs_dirops;
}
else {
optable = &semfs_semops;
}
semv = kmalloc(sizeof(*semv));
if (semv == NULL) {
return NULL;
}
semv->semv_semfs = semfs;
semv->semv_semnum = semnum;
result = vnode_init(&semv->semv_absvn, optable,
&semfs->semfs_absfs, semv);
/* vnode_init doesn't actually fail */
KASSERT(result == 0);
return semv;
}
/*
* Look up the vnode for a semaphore by number; if it doesn't exist,
* create it.
*/
int
semfs_getvnode(struct semfs *semfs, unsigned semnum, struct vnode **ret)
{
struct vnode *vn;
struct semfs_vnode *semv;
struct semfs_sem *sem;
unsigned i, num;
int result;
/* Lock the vnode table */
lock_acquire(semfs->semfs_tablelock);
/* Look for it */
num = vnodearray_num(semfs->semfs_vnodes);
for (i=0; i<num; i++) {
vn = vnodearray_get(semfs->semfs_vnodes, i);
semv = vn->vn_data;
if (semv->semv_semnum == semnum) {
VOP_INCREF(vn);
lock_release(semfs->semfs_tablelock);
*ret = vn;
return 0;
}
}
/* Make it */
semv = semfs_vnode_create(semfs, semnum);
if (semv == NULL) {
lock_release(semfs->semfs_tablelock);
return ENOMEM;
}
result = vnodearray_add(semfs->semfs_vnodes, &semv->semv_absvn, NULL);
if (result) {
semfs_vnode_destroy(semv);
lock_release(semfs->semfs_tablelock);
return ENOMEM;
}
if (semnum != SEMFS_ROOTDIR) {
sem = semfs_semarray_get(semfs->semfs_sems, semnum);
KASSERT(sem != NULL);
KASSERT(sem->sems_hasvnode == false);
sem->sems_hasvnode = true;
}
lock_release(semfs->semfs_tablelock);
*ret = &semv->semv_absvn;
return 0;
}

103
kern/fs/sfs/sfs_balloc.c Normal file
View File

@@ -0,0 +1,103 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* SFS filesystem
*
* Block allocation.
*/
#include <types.h>
#include <lib.h>
#include <bitmap.h>
#include <sfs.h>
#include "sfsprivate.h"
/*
* Zero out a disk block.
*/
static
int
sfs_clearblock(struct sfs_fs *sfs, daddr_t block)
{
/* static -> automatically initialized to zero */
static char zeros[SFS_BLOCKSIZE];
return sfs_writeblock(sfs, block, zeros, SFS_BLOCKSIZE);
}
/*
* Allocate a block.
*/
int
sfs_balloc(struct sfs_fs *sfs, daddr_t *diskblock)
{
int result;
result = bitmap_alloc(sfs->sfs_freemap, diskblock);
if (result) {
return result;
}
sfs->sfs_freemapdirty = true;
if (*diskblock >= sfs->sfs_sb.sb_nblocks) {
panic("sfs: %s: balloc: invalid block %u\n",
sfs->sfs_sb.sb_volname, *diskblock);
}
/* Clear block before returning it */
result = sfs_clearblock(sfs, *diskblock);
if (result) {
bitmap_unmark(sfs->sfs_freemap, *diskblock);
}
return result;
}
/*
* Free a block.
*/
void
sfs_bfree(struct sfs_fs *sfs, daddr_t diskblock)
{
bitmap_unmark(sfs->sfs_freemap, diskblock);
sfs->sfs_freemapdirty = true;
}
/*
* Check if a block is in use.
*/
int
sfs_bused(struct sfs_fs *sfs, daddr_t diskblock)
{
if (diskblock >= sfs->sfs_sb.sb_nblocks) {
panic("sfs: %s: sfs_bused called on out of range block %u\n",
sfs->sfs_sb.sb_volname, diskblock);
}
return bitmap_isset(sfs->sfs_freemap, diskblock);
}

303
kern/fs/sfs/sfs_bmap.c Normal file
View File

@@ -0,0 +1,303 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* SFS filesystem
*
* Block mapping logic.
*/
#include <types.h>
#include <kern/errno.h>
#include <lib.h>
#include <vfs.h>
#include <sfs.h>
#include "sfsprivate.h"
/*
* Look up the disk block number (from 0 up to the number of blocks on
* the disk) given a file and the logical block number within that
* file. If DOALLOC is set, and no such block exists, one will be
* allocated.
*/
int
sfs_bmap(struct sfs_vnode *sv, uint32_t fileblock, bool doalloc,
daddr_t *diskblock)
{
/*
* I/O buffer for handling indirect blocks.
*
* Note: in real life (and when you've done the fs assignment)
* you would get space from the disk buffer cache for this,
* not use a static area.
*/
static uint32_t idbuf[SFS_DBPERIDB];
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
daddr_t block;
daddr_t idblock;
uint32_t idnum, idoff;
int result;
KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);
/* Since we're using a static buffer, we'd better be locked. */
KASSERT(vfs_biglock_do_i_hold());
/*
* If the block we want is one of the direct blocks...
*/
if (fileblock < SFS_NDIRECT) {
/*
* Get the block number
*/
block = sv->sv_i.sfi_direct[fileblock];
/*
* Do we need to allocate?
*/
if (block==0 && doalloc) {
result = sfs_balloc(sfs, &block);
if (result) {
return result;
}
/* Remember what we allocated; mark inode dirty */
sv->sv_i.sfi_direct[fileblock] = block;
sv->sv_dirty = true;
}
/*
* Hand back the block
*/
if (block != 0 && !sfs_bused(sfs, block)) {
panic("sfs: %s: Data block %u (block %u of file %u) "
"marked free\n", sfs->sfs_sb.sb_volname,
block, fileblock, sv->sv_ino);
}
*diskblock = block;
return 0;
}
/*
* It's not a direct block; it must be in the indirect block.
* Subtract off the number of direct blocks, so FILEBLOCK is
* now the offset into the indirect block space.
*/
fileblock -= SFS_NDIRECT;
/* Get the indirect block number and offset w/i that indirect block */
idnum = fileblock / SFS_DBPERIDB;
idoff = fileblock % SFS_DBPERIDB;
/*
* We only have one indirect block. If the offset we were asked for
* is too large, we can't handle it, so fail.
*/
if (idnum >= SFS_NINDIRECT) {
return EFBIG;
}
/* Get the disk block number of the indirect block. */
idblock = sv->sv_i.sfi_indirect;
if (idblock==0 && !doalloc) {
/*
* There's no indirect block allocated. We weren't
* asked to allocate anything, so pretend the indirect
* block was filled with all zeros.
*/
*diskblock = 0;
return 0;
}
else if (idblock==0) {
/*
* There's no indirect block allocated, but we need to
* allocate a block whose number needs to be stored in
* the indirect block. Thus, we need to allocate an
* indirect block.
*/
result = sfs_balloc(sfs, &idblock);
if (result) {
return result;
}
/* Remember the block we just allocated */
sv->sv_i.sfi_indirect = idblock;
/* Mark the inode dirty */
sv->sv_dirty = true;
/* Clear the indirect block buffer */
bzero(idbuf, sizeof(idbuf));
}
else {
/*
* We already have an indirect block allocated; load it.
*/
result = sfs_readblock(sfs, idblock, idbuf, sizeof(idbuf));
if (result) {
return result;
}
}
/* Get the block out of the indirect block buffer */
block = idbuf[idoff];
/* If there's no block there, allocate one */
if (block==0 && doalloc) {
result = sfs_balloc(sfs, &block);
if (result) {
return result;
}
/* Remember the block we allocated */
idbuf[idoff] = block;
/* The indirect block is now dirty; write it back */
result = sfs_writeblock(sfs, idblock, idbuf, sizeof(idbuf));
if (result) {
return result;
}
}
/* Hand back the result and return. */
if (block != 0 && !sfs_bused(sfs, block)) {
panic("sfs: %s: Data block %u (block %u of file %u) "
"marked free\n", sfs->sfs_sb.sb_volname,
block, fileblock, sv->sv_ino);
}
*diskblock = block;
return 0;
}
/*
* Called for ftruncate() and from sfs_reclaim.
*/
int
sfs_itrunc(struct sfs_vnode *sv, off_t len)
{
/*
* I/O buffer for handling the indirect block.
*
* Note: in real life (and when you've done the fs assignment)
* you would get space from the disk buffer cache for this,
* not use a static area.
*/
static uint32_t idbuf[SFS_DBPERIDB];
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
/* Length in blocks (divide rounding up) */
uint32_t blocklen = DIVROUNDUP(len, SFS_BLOCKSIZE);
uint32_t i, j;
daddr_t block, idblock;
uint32_t baseblock, highblock;
int result;
int hasnonzero, iddirty;
KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);
vfs_biglock_acquire();
/*
* Go through the direct blocks. Discard any that are
* past the limit we're truncating to.
*/
for (i=0; i<SFS_NDIRECT; i++) {
block = sv->sv_i.sfi_direct[i];
if (i >= blocklen && block != 0) {
sfs_bfree(sfs, block);
sv->sv_i.sfi_direct[i] = 0;
sv->sv_dirty = true;
}
}
/* Indirect block number */
idblock = sv->sv_i.sfi_indirect;
/* The lowest block in the indirect block */
baseblock = SFS_NDIRECT;
/* The highest block in the indirect block */
highblock = baseblock + SFS_DBPERIDB - 1;
if (blocklen < highblock && idblock != 0) {
/* We're past the proposed EOF; may need to free stuff */
/* Read the indirect block */
result = sfs_readblock(sfs, idblock, idbuf, sizeof(idbuf));
if (result) {
vfs_biglock_release();
return result;
}
hasnonzero = 0;
iddirty = 0;
for (j=0; j<SFS_DBPERIDB; j++) {
/* Discard any blocks that are past the new EOF */
if (blocklen < baseblock+j && idbuf[j] != 0) {
sfs_bfree(sfs, idbuf[j]);
idbuf[j] = 0;
iddirty = 1;
}
/* Remember if we see any nonzero blocks in here */
if (idbuf[j]!=0) {
hasnonzero=1;
}
}
if (!hasnonzero) {
/* The whole indirect block is empty now; free it */
sfs_bfree(sfs, idblock);
sv->sv_i.sfi_indirect = 0;
sv->sv_dirty = true;
}
else if (iddirty) {
/* The indirect block is dirty; write it back */
result = sfs_writeblock(sfs, idblock, idbuf,
sizeof(idbuf));
if (result) {
vfs_biglock_release();
return result;
}
}
}
/* Set the file size */
sv->sv_i.sfi_size = len;
/* Mark the inode dirty */
sv->sv_dirty = true;
vfs_biglock_release();
return 0;
}

239
kern/fs/sfs/sfs_dir.c Normal file
View File

@@ -0,0 +1,239 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* SFS filesystem
*
* Directory I/O
*/
#include <types.h>
#include <kern/errno.h>
#include <lib.h>
#include <vfs.h>
#include <sfs.h>
#include "sfsprivate.h"
/*
* Read the directory entry out of slot SLOT of a directory vnode.
* The "slot" is the index of the directory entry, starting at 0.
*/
static
int
sfs_readdir(struct sfs_vnode *sv, int slot, struct sfs_direntry *sd)
{
off_t actualpos;
/* Compute the actual position in the directory to read. */
actualpos = slot * sizeof(struct sfs_direntry);
return sfs_metaio(sv, actualpos, sd, sizeof(*sd), UIO_READ);
}
/*
* Write (overwrite) the directory entry in slot SLOT of a directory
* vnode.
*/
static
int
sfs_writedir(struct sfs_vnode *sv, int slot, struct sfs_direntry *sd)
{
off_t actualpos;
/* Compute the actual position in the directory. */
KASSERT(slot>=0);
actualpos = slot * sizeof(struct sfs_direntry);
return sfs_metaio(sv, actualpos, sd, sizeof(*sd), UIO_WRITE);
}
/*
* Compute the number of entries in a directory.
* This actually computes the number of existing slots, and does not
* account for empty slots.
*/
static
int
sfs_dir_nentries(struct sfs_vnode *sv)
{
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
off_t size;
KASSERT(sv->sv_i.sfi_type == SFS_TYPE_DIR);
size = sv->sv_i.sfi_size;
if (size % sizeof(struct sfs_direntry) != 0) {
panic("sfs: %s: directory %u: Invalid size %llu\n",
sfs->sfs_sb.sb_volname, sv->sv_ino, size);
}
return size / sizeof(struct sfs_direntry);
}
/*
* Search a directory for a particular filename in a directory, and
* return its inode number, its slot, and/or the slot number of an
* empty directory slot if one is found.
*/
int
sfs_dir_findname(struct sfs_vnode *sv, const char *name,
uint32_t *ino, int *slot, int *emptyslot)
{
struct sfs_direntry tsd;
int found, nentries, i, result;
nentries = sfs_dir_nentries(sv);
/* For each slot... */
found = 0;
for (i=0; i<nentries; i++) {
/* Read the entry from that slot */
result = sfs_readdir(sv, i, &tsd);
if (result) {
return result;
}
if (tsd.sfd_ino == SFS_NOINO) {
/* Free slot - report it back if one was requested */
if (emptyslot != NULL) {
*emptyslot = i;
}
}
else {
/* Ensure null termination, just in case */
tsd.sfd_name[sizeof(tsd.sfd_name)-1] = 0;
if (!strcmp(tsd.sfd_name, name)) {
/* Each name may legally appear only once... */
KASSERT(found==0);
found = 1;
if (slot != NULL) {
*slot = i;
}
if (ino != NULL) {
*ino = tsd.sfd_ino;
}
}
}
}
return found ? 0 : ENOENT;
}
/*
* Create a link in a directory to the specified inode by number, with
* the specified name, and optionally hand back the slot.
*/
int
sfs_dir_link(struct sfs_vnode *sv, const char *name, uint32_t ino, int *slot)
{
int emptyslot = -1;
int result;
struct sfs_direntry sd;
/* Look up the name. We want to make sure it *doesn't* exist. */
result = sfs_dir_findname(sv, name, NULL, NULL, &emptyslot);
if (result!=0 && result!=ENOENT) {
return result;
}
if (result==0) {
return EEXIST;
}
if (strlen(name)+1 > sizeof(sd.sfd_name)) {
return ENAMETOOLONG;
}
/* If we didn't get an empty slot, add the entry at the end. */
if (emptyslot < 0) {
emptyslot = sfs_dir_nentries(sv);
}
/* Set up the entry. */
bzero(&sd, sizeof(sd));
sd.sfd_ino = ino;
strcpy(sd.sfd_name, name);
/* Hand back the slot, if so requested. */
if (slot) {
*slot = emptyslot;
}
/* Write the entry. */
return sfs_writedir(sv, emptyslot, &sd);
}
/*
* Unlink a name in a directory, by slot number.
*/
int
sfs_dir_unlink(struct sfs_vnode *sv, int slot)
{
struct sfs_direntry sd;
/* Initialize a suitable directory entry... */
bzero(&sd, sizeof(sd));
sd.sfd_ino = SFS_NOINO;
/* ... and write it */
return sfs_writedir(sv, slot, &sd);
}
/*
* Look for a name in a directory and hand back a vnode for the
* file, if there is one.
*/
int
sfs_lookonce(struct sfs_vnode *sv, const char *name,
struct sfs_vnode **ret,
int *slot)
{
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
uint32_t ino;
int result;
result = sfs_dir_findname(sv, name, &ino, slot, NULL);
if (result) {
return result;
}
result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, ret);
if (result) {
return result;
}
if ((*ret)->sv_i.sfi_linkcount == 0) {
panic("sfs: %s: name %s (inode %u) in dir %u has "
"linkcount 0\n", sfs->sfs_sb.sb_volname,
name, (*ret)->sv_ino, sv->sv_ino);
}
return 0;
}

481
kern/fs/sfs/sfs_fsops.c Normal file
View File

@@ -0,0 +1,481 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* SFS filesystem
*
* Filesystem-level interface routines.
*/
#include <types.h>
#include <kern/errno.h>
#include <lib.h>
#include <array.h>
#include <bitmap.h>
#include <uio.h>
#include <vfs.h>
#include <device.h>
#include <sfs.h>
#include "sfsprivate.h"
/* Shortcuts for the size macros in kern/sfs.h */
#define SFS_FS_NBLOCKS(sfs) ((sfs)->sfs_sb.sb_nblocks)
#define SFS_FS_FREEMAPBITS(sfs) SFS_FREEMAPBITS(SFS_FS_NBLOCKS(sfs))
#define SFS_FS_FREEMAPBLOCKS(sfs) SFS_FREEMAPBLOCKS(SFS_FS_NBLOCKS(sfs))
/*
* Routine for doing I/O (reads or writes) on the free block bitmap.
* We always do the whole bitmap at once; writing individual sectors
* might or might not be a worthwhile optimization.
*
* The free block bitmap consists of SFS_FREEMAPBLOCKS 512-byte
* sectors of bits, one bit for each sector on the filesystem. The
* number of blocks in the bitmap is thus rounded up to the nearest
* multiple of 512*8 = 4096. (This rounded number is SFS_FREEMAPBITS.)
* This means that the bitmap will (in general) contain space for some
* number of invalid sectors that are actually beyond the end of the
* disk device. This is ok. These sectors are supposed to be marked
* "in use" by mksfs and never get marked "free".
*
* The sectors used by the superblock and the bitmap itself are
* likewise marked in use by mksfs.
*/
static
int
sfs_freemapio(struct sfs_fs *sfs, enum uio_rw rw)
{
uint32_t j, freemapblocks;
char *freemapdata;
int result;
/* Number of blocks in the free block bitmap. */
freemapblocks = SFS_FS_FREEMAPBLOCKS(sfs);
/* Pointer to our freemap data in memory. */
freemapdata = bitmap_getdata(sfs->sfs_freemap);
/* For each block in the free block bitmap... */
for (j=0; j<freemapblocks; j++) {
/* Get a pointer to its data */
void *ptr = freemapdata + j*SFS_BLOCKSIZE;
/* and read or write it. The freemap starts at sector 2. */
if (rw == UIO_READ) {
result = sfs_readblock(sfs, SFS_FREEMAP_START+j, ptr,
SFS_BLOCKSIZE);
}
else {
result = sfs_writeblock(sfs, SFS_FREEMAP_START+j, ptr,
SFS_BLOCKSIZE);
}
/* If we failed, stop. */
if (result) {
return result;
}
}
return 0;
}
/*
* Sync routine for the vnode table.
*/
static
int
sfs_sync_vnodes(struct sfs_fs *sfs)
{
unsigned i, num;
/* Go over the array of loaded vnodes, syncing as we go. */
num = vnodearray_num(sfs->sfs_vnodes);
for (i=0; i<num; i++) {
struct vnode *v = vnodearray_get(sfs->sfs_vnodes, i);
VOP_FSYNC(v);
}
return 0;
}
/*
* Sync routine for the freemap.
*/
static
int
sfs_sync_freemap(struct sfs_fs *sfs)
{
int result;
if (sfs->sfs_freemapdirty) {
result = sfs_freemapio(sfs, UIO_WRITE);
if (result) {
return result;
}
sfs->sfs_freemapdirty = false;
}
return 0;
}
/*
* Sync routine for the superblock.
*/
static
int
sfs_sync_superblock(struct sfs_fs *sfs)
{
int result;
if (sfs->sfs_superdirty) {
result = sfs_writeblock(sfs, SFS_SUPER_BLOCK, &sfs->sfs_sb,
sizeof(sfs->sfs_sb));
if (result) {
return result;
}
sfs->sfs_superdirty = false;
}
return 0;
}
/*
* Sync routine. This is what gets invoked if you do FS_SYNC on the
* sfs filesystem structure.
*/
static
int
sfs_sync(struct fs *fs)
{
struct sfs_fs *sfs;
int result;
vfs_biglock_acquire();
/*
* Get the sfs_fs from the generic abstract fs.
*
* Note that the abstract struct fs, which is all the VFS
* layer knows about, is actually a member of struct sfs_fs.
* The pointer in the struct fs points back to the top of the
* struct sfs_fs - essentially the same object. This can be a
* little confusing at first.
*
* The following diagram may help:
*
* struct sfs_fs <-------------\
* : |
* : sfs_absfs (struct fs) | <------\
* : : | |
* : : various members | |
* : : | |
* : : fs_data ----------/ |
* : : ...|...
* : . VFS .
* : . layer .
* : other members .......
* :
* :
*
* This construct is repeated with vnodes and devices and other
* similar things all over the place in OS/161, so taking the
* time to straighten it out in your mind is worthwhile.
*/
sfs = fs->fs_data;
/* If any vnodes need to be written, write them. */
result = sfs_sync_vnodes(sfs);
if (result) {
vfs_biglock_release();
return result;
}
/* If the free block map needs to be written, write it. */
result = sfs_sync_freemap(sfs);
if (result) {
vfs_biglock_release();
return result;
}
/* If the superblock needs to be written, write it. */
result = sfs_sync_superblock(sfs);
if (result) {
vfs_biglock_release();
return result;
}
vfs_biglock_release();
return 0;
}
/*
* Routine to retrieve the volume name. Filesystems can be referred
* to by their volume name followed by a colon as well as the name
* of the device they're mounted on.
*/
static
const char *
sfs_getvolname(struct fs *fs)
{
struct sfs_fs *sfs = fs->fs_data;
const char *ret;
vfs_biglock_acquire();
ret = sfs->sfs_sb.sb_volname;
vfs_biglock_release();
return ret;
}
/*
* Destructor for struct sfs_fs.
*/
static
void
sfs_fs_destroy(struct sfs_fs *sfs)
{
if (sfs->sfs_freemap != NULL) {
bitmap_destroy(sfs->sfs_freemap);
}
vnodearray_destroy(sfs->sfs_vnodes);
KASSERT(sfs->sfs_device == NULL);
kfree(sfs);
}
/*
* Unmount code.
*
* VFS calls FS_SYNC on the filesystem prior to unmounting it.
*/
static
int
sfs_unmount(struct fs *fs)
{
struct sfs_fs *sfs = fs->fs_data;
vfs_biglock_acquire();
/* Do we have any files open? If so, can't unmount. */
if (vnodearray_num(sfs->sfs_vnodes) > 0) {
vfs_biglock_release();
return EBUSY;
}
/* We should have just had sfs_sync called. */
KASSERT(sfs->sfs_superdirty == false);
KASSERT(sfs->sfs_freemapdirty == false);
/* The vfs layer takes care of the device for us */
sfs->sfs_device = NULL;
/* Destroy the fs object; once we start nuking stuff we can't fail. */
sfs_fs_destroy(sfs);
/* nothing else to do */
vfs_biglock_release();
return 0;
}
/*
* File system operations table.
*/
static const struct fs_ops sfs_fsops = {
.fsop_sync = sfs_sync,
.fsop_getvolname = sfs_getvolname,
.fsop_getroot = sfs_getroot,
.fsop_unmount = sfs_unmount,
};
/*
* Basic constructor for struct sfs_fs. This initializes all fields
* but skips stuff that requires reading the volume, like allocating
* the freemap.
*/
static
struct sfs_fs *
sfs_fs_create(void)
{
struct sfs_fs *sfs;
/*
* Make sure our on-disk structures aren't messed up
*/
COMPILE_ASSERT(sizeof(struct sfs_superblock)==SFS_BLOCKSIZE);
COMPILE_ASSERT(sizeof(struct sfs_dinode)==SFS_BLOCKSIZE);
COMPILE_ASSERT(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
/* Allocate object */
sfs = kmalloc(sizeof(struct sfs_fs));
if (sfs==NULL) {
goto fail;
}
/*
* Fill in fields
*/
/* abstract vfs-level fs */
sfs->sfs_absfs.fs_data = sfs;
sfs->sfs_absfs.fs_ops = &sfs_fsops;
/* superblock */
/* (ignore sfs_super, we'll read in over it shortly) */
sfs->sfs_superdirty = false;
/* device we mount on */
sfs->sfs_device = NULL;
/* vnode table */
sfs->sfs_vnodes = vnodearray_create();
if (sfs->sfs_vnodes == NULL) {
goto cleanup_object;
}
/* freemap */
sfs->sfs_freemap = NULL;
sfs->sfs_freemapdirty = false;
return sfs;
cleanup_object:
kfree(sfs);
fail:
return NULL;
}
/*
* Mount routine.
*
* The way mount works is that you call vfs_mount and pass it a
* filesystem-specific mount routine. Said routine takes a device and
* hands back a pointer to an abstract filesystem. You can also pass
* a void pointer through.
*
* This organization makes cleanup on error easier. Hint: it may also
* be easier to synchronize correctly; it is important not to get two
* filesystems with the same name mounted at once, or two filesystems
* mounted on the same device at once.
*/
static
int
sfs_domount(void *options, struct device *dev, struct fs **ret)
{
int result;
struct sfs_fs *sfs;
vfs_biglock_acquire();
/* We don't pass any options through mount */
(void)options;
/*
* We can't mount on devices with the wrong sector size.
*
* (Note: for all intents and purposes here, "sector" and
* "block" are interchangeable terms. Technically a filesystem
* block may be composed of several hardware sectors, but we
* don't do that in sfs.)
*/
if (dev->d_blocksize != SFS_BLOCKSIZE) {
vfs_biglock_release();
kprintf("sfs: Cannot mount on device with blocksize %zu\n",
dev->d_blocksize);
return ENXIO;
}
sfs = sfs_fs_create();
if (sfs == NULL) {
vfs_biglock_release();
return ENOMEM;
}
/* Set the device so we can use sfs_readblock() */
sfs->sfs_device = dev;
/* Load superblock */
result = sfs_readblock(sfs, SFS_SUPER_BLOCK, &sfs->sfs_sb,
sizeof(sfs->sfs_sb));
if (result) {
sfs->sfs_device = NULL;
sfs_fs_destroy(sfs);
vfs_biglock_release();
return result;
}
/* Make some simple sanity checks */
if (sfs->sfs_sb.sb_magic != SFS_MAGIC) {
kprintf("sfs: Wrong magic number in superblock "
"(0x%x, should be 0x%x)\n",
sfs->sfs_sb.sb_magic,
SFS_MAGIC);
sfs->sfs_device = NULL;
sfs_fs_destroy(sfs);
vfs_biglock_release();
return EINVAL;
}
if (sfs->sfs_sb.sb_nblocks > dev->d_blocks) {
kprintf("sfs: warning - fs has %u blocks, device has %u\n",
sfs->sfs_sb.sb_nblocks, dev->d_blocks);
}
/* Ensure null termination of the volume name */
sfs->sfs_sb.sb_volname[sizeof(sfs->sfs_sb.sb_volname)-1] = 0;
/* Load free block bitmap */
sfs->sfs_freemap = bitmap_create(SFS_FS_FREEMAPBITS(sfs));
if (sfs->sfs_freemap == NULL) {
sfs->sfs_device = NULL;
sfs_fs_destroy(sfs);
vfs_biglock_release();
return ENOMEM;
}
result = sfs_freemapio(sfs, UIO_READ);
if (result) {
sfs->sfs_device = NULL;
sfs_fs_destroy(sfs);
vfs_biglock_release();
return result;
}
/* Hand back the abstract fs */
*ret = &sfs->sfs_absfs;
vfs_biglock_release();
return 0;
}
/*
* Actual function called from high-level code to mount an sfs.
*/
int
sfs_mount(const char *device)
{
return vfs_mount(device, NULL, sfs_domount);
}

320
kern/fs/sfs/sfs_inode.c Normal file
View File

@@ -0,0 +1,320 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* SFS filesystem
*
* Inode-level operations and vnode/inode lifecycle logic.
*/
#include <types.h>
#include <kern/errno.h>
#include <lib.h>
#include <vfs.h>
#include <sfs.h>
#include "sfsprivate.h"
/*
* Write an on-disk inode structure back out to disk.
*/
int
sfs_sync_inode(struct sfs_vnode *sv)
{
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
int result;
if (sv->sv_dirty) {
result = sfs_writeblock(sfs, sv->sv_ino, &sv->sv_i,
sizeof(sv->sv_i));
if (result) {
return result;
}
sv->sv_dirty = false;
}
return 0;
}
/*
* Called when the vnode refcount (in-memory usage count) hits zero.
*
* This function should try to avoid returning errors other than EBUSY.
*/
int
sfs_reclaim(struct vnode *v)
{
struct sfs_vnode *sv = v->vn_data;
struct sfs_fs *sfs = v->vn_fs->fs_data;
unsigned ix, i, num;
int result;
vfs_biglock_acquire();
/*
* Make sure someone else hasn't picked up the vnode since the
* decision was made to reclaim it. (You must also synchronize
* this with sfs_loadvnode.)
*/
spinlock_acquire(&v->vn_countlock);
if (v->vn_refcount != 1) {
/* consume the reference VOP_DECREF gave us */
KASSERT(v->vn_refcount>1);
v->vn_refcount--;
spinlock_release(&v->vn_countlock);
vfs_biglock_release();
return EBUSY;
}
spinlock_release(&v->vn_countlock);
/* If there are no on-disk references to the file either, erase it. */
if (sv->sv_i.sfi_linkcount == 0) {
result = sfs_itrunc(sv, 0);
if (result) {
vfs_biglock_release();
return result;
}
}
/* Sync the inode to disk */
result = sfs_sync_inode(sv);
if (result) {
vfs_biglock_release();
return result;
}
/* If there are no on-disk references, discard the inode */
if (sv->sv_i.sfi_linkcount==0) {
sfs_bfree(sfs, sv->sv_ino);
}
/* Remove the vnode structure from the table in the struct sfs_fs. */
num = vnodearray_num(sfs->sfs_vnodes);
ix = num;
for (i=0; i<num; i++) {
struct vnode *v2 = vnodearray_get(sfs->sfs_vnodes, i);
struct sfs_vnode *sv2 = v2->vn_data;
if (sv2 == sv) {
ix = i;
break;
}
}
if (ix == num) {
panic("sfs: %s: reclaim vnode %u not in vnode pool\n",
sfs->sfs_sb.sb_volname, sv->sv_ino);
}
vnodearray_remove(sfs->sfs_vnodes, ix);
vnode_cleanup(&sv->sv_absvn);
vfs_biglock_release();
/* Release the storage for the vnode structure itself. */
kfree(sv);
/* Done */
return 0;
}
/*
* Function to load a inode into memory as a vnode, or dig up one
* that's already resident.
*/
int
sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int forcetype,
struct sfs_vnode **ret)
{
struct vnode *v;
struct sfs_vnode *sv;
const struct vnode_ops *ops;
unsigned i, num;
int result;
/* Look in the vnodes table */
num = vnodearray_num(sfs->sfs_vnodes);
/* Linear search. Is this too slow? You decide. */
for (i=0; i<num; i++) {
v = vnodearray_get(sfs->sfs_vnodes, i);
sv = v->vn_data;
/* Every inode in memory must be in an allocated block */
if (!sfs_bused(sfs, sv->sv_ino)) {
panic("sfs: %s: Found inode %u in unallocated block\n",
sfs->sfs_sb.sb_volname, sv->sv_ino);
}
if (sv->sv_ino==ino) {
/* Found */
/* forcetype is only allowed when creating objects */
KASSERT(forcetype==SFS_TYPE_INVAL);
VOP_INCREF(&sv->sv_absvn);
*ret = sv;
return 0;
}
}
/* Didn't have it loaded; load it */
sv = kmalloc(sizeof(struct sfs_vnode));
if (sv==NULL) {
return ENOMEM;
}
/* Must be in an allocated block */
if (!sfs_bused(sfs, ino)) {
panic("sfs: %s: Tried to load inode %u from "
"unallocated block\n", sfs->sfs_sb.sb_volname, ino);
}
/* Read the block the inode is in */
result = sfs_readblock(sfs, ino, &sv->sv_i, sizeof(sv->sv_i));
if (result) {
kfree(sv);
return result;
}
/* Not dirty yet */
sv->sv_dirty = false;
/*
* FORCETYPE is set if we're creating a new file, because the
* block on disk will have been zeroed out by sfs_balloc and
* thus the type recorded there will be SFS_TYPE_INVAL.
*/
if (forcetype != SFS_TYPE_INVAL) {
KASSERT(sv->sv_i.sfi_type == SFS_TYPE_INVAL);
sv->sv_i.sfi_type = forcetype;
sv->sv_dirty = true;
}
/*
* Choose the function table based on the object type.
*/
switch (sv->sv_i.sfi_type) {
case SFS_TYPE_FILE:
ops = &sfs_fileops;
break;
case SFS_TYPE_DIR:
ops = &sfs_dirops;
break;
default:
panic("sfs: %s: loadvnode: Invalid inode type "
"(inode %u, type %u)\n", sfs->sfs_sb.sb_volname,
ino, sv->sv_i.sfi_type);
}
/* Call the common vnode initializer */
result = vnode_init(&sv->sv_absvn, ops, &sfs->sfs_absfs, sv);
if (result) {
kfree(sv);
return result;
}
/* Set the other fields in our vnode structure */
sv->sv_ino = ino;
/* Add it to our table */
result = vnodearray_add(sfs->sfs_vnodes, &sv->sv_absvn, NULL);
if (result) {
vnode_cleanup(&sv->sv_absvn);
kfree(sv);
return result;
}
/* Hand it back */
*ret = sv;
return 0;
}
/*
* Create a new filesystem object and hand back its vnode.
*/
int
sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret)
{
uint32_t ino;
int result;
/*
* First, get an inode. (Each inode is a block, and the inode
* number is the block number, so just get a block.)
*/
result = sfs_balloc(sfs, &ino);
if (result) {
return result;
}
/*
* Now load a vnode for it.
*/
result = sfs_loadvnode(sfs, ino, type, ret);
if (result) {
sfs_bfree(sfs, ino);
}
return result;
}
/*
* Get vnode for the root of the filesystem.
* The root vnode is always found in block 1 (SFS_ROOTDIR_INO).
*/
int
sfs_getroot(struct fs *fs, struct vnode **ret)
{
struct sfs_fs *sfs = fs->fs_data;
struct sfs_vnode *sv;
int result;
vfs_biglock_acquire();
result = sfs_loadvnode(sfs, SFS_ROOTDIR_INO, SFS_TYPE_INVAL, &sv);
if (result) {
kprintf("sfs: %s: getroot: Cannot load root vnode\n",
sfs->sfs_sb.sb_volname);
vfs_biglock_release();
return result;
}
if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
kprintf("sfs: %s: getroot: not directory (type %u)\n",
sfs->sfs_sb.sb_volname, sv->sv_i.sfi_type);
vfs_biglock_release();
return EINVAL;
}
vfs_biglock_release();
*ret = &sv->sv_absvn;
return 0;
}

480
kern/fs/sfs/sfs_io.c Normal file
View File

@@ -0,0 +1,480 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* SFS filesystem
*
* I/O plumbing.
*/
#include <types.h>
#include <kern/errno.h>
#include <lib.h>
#include <uio.h>
#include <vfs.h>
#include <device.h>
#include <sfs.h>
#include "sfsprivate.h"
////////////////////////////////////////////////////////////
//
// Basic block-level I/O routines
/*
* Note: sfs_readblock is used to read the superblock
* early in mount, before sfs is fully (or even mostly)
* initialized, and so may not use anything from sfs
* except sfs_device.
*/
/*
* Read or write a block, retrying I/O errors.
*/
static
int
sfs_rwblock(struct sfs_fs *sfs, struct uio *uio)
{
int result;
int tries=0;
KASSERT(vfs_biglock_do_i_hold());
DEBUG(DB_SFS, "sfs: %s %llu\n",
uio->uio_rw == UIO_READ ? "read" : "write",
uio->uio_offset / SFS_BLOCKSIZE);
retry:
result = DEVOP_IO(sfs->sfs_device, uio);
if (result == EINVAL) {
/*
* This means the sector we requested was out of range,
* or the seek address we gave wasn't sector-aligned,
* or a couple of other things that are our fault.
*/
panic("sfs: %s: DEVOP_IO returned EINVAL\n",
sfs->sfs_sb.sb_volname);
}
if (result == EIO) {
if (tries == 0) {
tries++;
kprintf("sfs: %s: block %llu I/O error, retrying\n",
sfs->sfs_sb.sb_volname,
uio->uio_offset / SFS_BLOCKSIZE);
goto retry;
}
else if (tries < 10) {
tries++;
goto retry;
}
else {
kprintf("sfs: %s: block %llu I/O error, giving up "
"after %d retries\n",
sfs->sfs_sb.sb_volname,
uio->uio_offset / SFS_BLOCKSIZE, tries);
}
}
return result;
}
/*
* Read a block.
*/
int
sfs_readblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len)
{
struct iovec iov;
struct uio ku;
KASSERT(len == SFS_BLOCKSIZE);
SFSUIO(&iov, &ku, data, block, UIO_READ);
return sfs_rwblock(sfs, &ku);
}
/*
* Write a block.
*/
int
sfs_writeblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len)
{
struct iovec iov;
struct uio ku;
KASSERT(len == SFS_BLOCKSIZE);
SFSUIO(&iov, &ku, data, block, UIO_WRITE);
return sfs_rwblock(sfs, &ku);
}
////////////////////////////////////////////////////////////
//
// File-level I/O
/*
* Do I/O to a block of a file that doesn't cover the whole block. We
* need to read in the original block first, even if we're writing, so
* we don't clobber the portion of the block we're not intending to
* write over.
*
* SKIPSTART is the number of bytes to skip past at the beginning of
* the sector; LEN is the number of bytes to actually read or write.
* UIO is the area to do the I/O into.
*/
static
int
sfs_partialio(struct sfs_vnode *sv, struct uio *uio,
uint32_t skipstart, uint32_t len)
{
/*
* I/O buffer for handling partial sectors.
*
* Note: in real life (and when you've done the fs assignment)
* you would get space from the disk buffer cache for this,
* not use a static area.
*/
static char iobuf[SFS_BLOCKSIZE];
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
daddr_t diskblock;
uint32_t fileblock;
int result;
/* Allocate missing blocks if and only if we're writing */
bool doalloc = (uio->uio_rw==UIO_WRITE);
KASSERT(skipstart + len <= SFS_BLOCKSIZE);
/* We're using a global static buffer; it had better be locked */
KASSERT(vfs_biglock_do_i_hold());
/* Compute the block offset of this block in the file */
fileblock = uio->uio_offset / SFS_BLOCKSIZE;
/* Get the disk block number */
result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
if (result) {
return result;
}
if (diskblock == 0) {
/*
* There was no block mapped at this point in the file.
* Zero the buffer.
*/
KASSERT(uio->uio_rw == UIO_READ);
bzero(iobuf, sizeof(iobuf));
}
else {
/*
* Read the block.
*/
result = sfs_readblock(sfs, diskblock, iobuf, sizeof(iobuf));
if (result) {
return result;
}
}
/*
* Now perform the requested operation into/out of the buffer.
*/
result = uiomove(iobuf+skipstart, len, uio);
if (result) {
return result;
}
/*
* If it was a write, write back the modified block.
*/
if (uio->uio_rw == UIO_WRITE) {
result = sfs_writeblock(sfs, diskblock, iobuf, sizeof(iobuf));
if (result) {
return result;
}
}
return 0;
}
/*
* Do I/O (either read or write) of a single whole block.
*/
static
int
sfs_blockio(struct sfs_vnode *sv, struct uio *uio)
{
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
daddr_t diskblock;
uint32_t fileblock;
int result;
bool doalloc = (uio->uio_rw==UIO_WRITE);
off_t saveoff;
off_t diskoff;
off_t saveres;
off_t diskres;
/* Get the block number within the file */
fileblock = uio->uio_offset / SFS_BLOCKSIZE;
/* Look up the disk block number */
result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
if (result) {
return result;
}
if (diskblock == 0) {
/*
* No block - fill with zeros.
*
* We must be reading, or sfs_bmap would have
* allocated a block for us.
*/
KASSERT(uio->uio_rw == UIO_READ);
return uiomovezeros(SFS_BLOCKSIZE, uio);
}
/*
* Do the I/O directly to the uio region. Save the uio_offset,
* and substitute one that makes sense to the device.
*/
saveoff = uio->uio_offset;
diskoff = diskblock * SFS_BLOCKSIZE;
uio->uio_offset = diskoff;
/*
* Temporarily set the residue to be one block size.
*/
KASSERT(uio->uio_resid >= SFS_BLOCKSIZE);
saveres = uio->uio_resid;
diskres = SFS_BLOCKSIZE;
uio->uio_resid = diskres;
result = sfs_rwblock(sfs, uio);
/*
* Now, restore the original uio_offset and uio_resid and update
* them by the amount of I/O done.
*/
uio->uio_offset = (uio->uio_offset - diskoff) + saveoff;
uio->uio_resid = (uio->uio_resid - diskres) + saveres;
return result;
}
/*
* Do I/O of a whole region of data, whether or not it's block-aligned.
*/
int
sfs_io(struct sfs_vnode *sv, struct uio *uio)
{
uint32_t blkoff;
uint32_t nblocks, i;
int result = 0;
uint32_t origresid, extraresid = 0;
origresid = uio->uio_resid;
/*
* If reading, check for EOF. If we can read a partial area,
* remember how much extra there was in EXTRARESID so we can
* add it back to uio_resid at the end.
*/
if (uio->uio_rw == UIO_READ) {
off_t size = sv->sv_i.sfi_size;
off_t endpos = uio->uio_offset + uio->uio_resid;
if (uio->uio_offset >= size) {
/* At or past EOF - just return */
return 0;
}
if (endpos > size) {
extraresid = endpos - size;
KASSERT(uio->uio_resid > extraresid);
uio->uio_resid -= extraresid;
}
}
/*
* First, do any leading partial block.
*/
blkoff = uio->uio_offset % SFS_BLOCKSIZE;
if (blkoff != 0) {
/* Number of bytes at beginning of block to skip */
uint32_t skip = blkoff;
/* Number of bytes to read/write after that point */
uint32_t len = SFS_BLOCKSIZE - blkoff;
/* ...which might be less than the rest of the block */
if (len > uio->uio_resid) {
len = uio->uio_resid;
}
/* Call sfs_partialio() to do it. */
result = sfs_partialio(sv, uio, skip, len);
if (result) {
goto out;
}
}
/* If we're done, quit. */
if (uio->uio_resid==0) {
goto out;
}
/*
* Now we should be block-aligned. Do the remaining whole blocks.
*/
KASSERT(uio->uio_offset % SFS_BLOCKSIZE == 0);
nblocks = uio->uio_resid / SFS_BLOCKSIZE;
for (i=0; i<nblocks; i++) {
result = sfs_blockio(sv, uio);
if (result) {
goto out;
}
}
/*
* Now do any remaining partial block at the end.
*/
KASSERT(uio->uio_resid < SFS_BLOCKSIZE);
if (uio->uio_resid > 0) {
result = sfs_partialio(sv, uio, 0, uio->uio_resid);
if (result) {
goto out;
}
}
out:
/* If writing and we did anything, adjust file length */
if (uio->uio_resid != origresid &&
uio->uio_rw == UIO_WRITE &&
uio->uio_offset > (off_t)sv->sv_i.sfi_size) {
sv->sv_i.sfi_size = uio->uio_offset;
sv->sv_dirty = true;
}
/* Add in any extra amount we couldn't read because of EOF */
uio->uio_resid += extraresid;
/* Done */
return result;
}
////////////////////////////////////////////////////////////
// Metadata I/O
/*
* This is much the same as sfs_partialio, but intended for use with
* metadata (e.g. directory entries). It assumes the objects being
* handled are smaller than whole blocks, do not cross block
* boundaries, and originate in the kernel.
*
* It is separate from sfs_partialio because, although there is no
* such code in this version of SFS, it is often desirable when doing
* more advanced things to handle metadata and user data I/O
* differently.
*/
int
sfs_metaio(struct sfs_vnode *sv, off_t actualpos, void *data, size_t len,
enum uio_rw rw)
{
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
off_t endpos;
uint32_t vnblock;
uint32_t blockoffset;
daddr_t diskblock;
bool doalloc;
int result;
/*
* I/O buffer for metadata ops.
*
* Note: in real life (and when you've done the fs assignment) you
* would get space from the disk buffer cache for this, not use a
* static area.
*/
static char metaiobuf[SFS_BLOCKSIZE];
/* We're using a global static buffer; it had better be locked */
KASSERT(vfs_biglock_do_i_hold());
/* Figure out which block of the vnode (directory, whatever) this is */
vnblock = actualpos / SFS_BLOCKSIZE;
blockoffset = actualpos % SFS_BLOCKSIZE;
/* Get the disk block number */
doalloc = (rw == UIO_WRITE);
result = sfs_bmap(sv, vnblock, doalloc, &diskblock);
if (result) {
return result;
}
if (diskblock == 0) {
/* Should only get block 0 back if doalloc is false */
KASSERT(rw == UIO_READ);
/* Sparse file, read as zeros. */
bzero(data, len);
return 0;
}
/* Read the block */
result = sfs_readblock(sfs, diskblock, metaiobuf, sizeof(metaiobuf));
if (result) {
return result;
}
if (rw == UIO_READ) {
/* Copy out the selected region */
memcpy(data, metaiobuf + blockoffset, len);
}
else {
/* Update the selected region */
memcpy(metaiobuf + blockoffset, data, len);
/* Write the block back */
result = sfs_writeblock(sfs, diskblock,
metaiobuf, sizeof(metaiobuf));
if (result) {
return result;
}
/* Update the vnode size if needed */
endpos = actualpos + len;
if (endpos > (off_t)sv->sv_i.sfi_size) {
sv->sv_i.sfi_size = endpos;
sv->sv_dirty = true;
}
}
/* Done */
return 0;
}

650
kern/fs/sfs/sfs_vnops.c Normal file
View File

@@ -0,0 +1,650 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* SFS filesystem
*
* File-level (vnode) interface routines.
*/
#include <types.h>
#include <kern/errno.h>
#include <kern/fcntl.h>
#include <stat.h>
#include <lib.h>
#include <uio.h>
#include <vfs.h>
#include <sfs.h>
#include "sfsprivate.h"
////////////////////////////////////////////////////////////
// Vnode operations.
/*
* This is called on *each* open().
*/
static
int
sfs_eachopen(struct vnode *v, int openflags)
{
/*
* At this level we do not need to handle O_CREAT, O_EXCL,
* O_TRUNC, or O_APPEND.
*
* Any of O_RDONLY, O_WRONLY, and O_RDWR are valid, so we don't need
* to check that either.
*/
(void)v;
(void)openflags;
return 0;
}
/*
* This is called on *each* open() of a directory.
* Directories may only be open for read.
*/
static
int
sfs_eachopendir(struct vnode *v, int openflags)
{
switch (openflags & O_ACCMODE) {
case O_RDONLY:
break;
case O_WRONLY:
case O_RDWR:
default:
return EISDIR;
}
if (openflags & O_APPEND) {
return EISDIR;
}
(void)v;
return 0;
}
/*
* Called for read(). sfs_io() does the work.
*/
static
int
sfs_read(struct vnode *v, struct uio *uio)
{
struct sfs_vnode *sv = v->vn_data;
int result;
KASSERT(uio->uio_rw==UIO_READ);
vfs_biglock_acquire();
result = sfs_io(sv, uio);
vfs_biglock_release();
return result;
}
/*
* Called for write(). sfs_io() does the work.
*/
static
int
sfs_write(struct vnode *v, struct uio *uio)
{
struct sfs_vnode *sv = v->vn_data;
int result;
KASSERT(uio->uio_rw==UIO_WRITE);
vfs_biglock_acquire();
result = sfs_io(sv, uio);
vfs_biglock_release();
return result;
}
/*
* Called for ioctl()
*/
static
int
sfs_ioctl(struct vnode *v, int op, userptr_t data)
{
/*
* No ioctls.
*/
(void)v;
(void)op;
(void)data;
return EINVAL;
}
/*
* Called for stat/fstat/lstat.
*/
static
int
sfs_stat(struct vnode *v, struct stat *statbuf)
{
struct sfs_vnode *sv = v->vn_data;
int result;
/* Fill in the stat structure */
bzero(statbuf, sizeof(struct stat));
result = VOP_GETTYPE(v, &statbuf->st_mode);
if (result) {
return result;
}
statbuf->st_size = sv->sv_i.sfi_size;
statbuf->st_nlink = sv->sv_i.sfi_linkcount;
/* We don't support this yet */
statbuf->st_blocks = 0;
/* Fill in other fields as desired/possible... */
return 0;
}
/*
* Return the type of the file (types as per kern/stat.h)
*/
static
int
sfs_gettype(struct vnode *v, uint32_t *ret)
{
struct sfs_vnode *sv = v->vn_data;
struct sfs_fs *sfs = v->vn_fs->fs_data;
vfs_biglock_acquire();
switch (sv->sv_i.sfi_type) {
case SFS_TYPE_FILE:
*ret = S_IFREG;
vfs_biglock_release();
return 0;
case SFS_TYPE_DIR:
*ret = S_IFDIR;
vfs_biglock_release();
return 0;
}
panic("sfs: %s: gettype: Invalid inode type (inode %u, type %u)\n",
sfs->sfs_sb.sb_volname, sv->sv_ino, sv->sv_i.sfi_type);
return EINVAL;
}
/*
* Check if seeking is allowed. The answer is "yes".
*/
static
bool
sfs_isseekable(struct vnode *v)
{
(void)v;
return true;
}
/*
* Called for fsync(), and also on filesystem unmount, global sync(),
* and some other cases.
*/
static
int
sfs_fsync(struct vnode *v)
{
struct sfs_vnode *sv = v->vn_data;
int result;
vfs_biglock_acquire();
result = sfs_sync_inode(sv);
vfs_biglock_release();
return result;
}
/*
* Called for mmap().
*/
static
int
sfs_mmap(struct vnode *v /* add stuff as needed */)
{
(void)v;
return ENOSYS;
}
/*
* Truncate a file.
*/
static
int
sfs_truncate(struct vnode *v, off_t len)
{
struct sfs_vnode *sv = v->vn_data;
return sfs_itrunc(sv, len);
}
/*
* Get the full pathname for a file. This only needs to work on directories.
* Since we don't support subdirectories, assume it's the root directory
* and hand back the empty string. (The VFS layer takes care of the
* device name, leading slash, etc.)
*/
static
int
sfs_namefile(struct vnode *vv, struct uio *uio)
{
struct sfs_vnode *sv = vv->vn_data;
KASSERT(sv->sv_ino == SFS_ROOTDIR_INO);
/* send back the empty string - just return */
(void)uio;
return 0;
}
/*
* Create a file. If EXCL is set, insist that the filename not already
* exist; otherwise, if it already exists, just open it.
*/
static
int
sfs_creat(struct vnode *v, const char *name, bool excl, mode_t mode,
struct vnode **ret)
{
struct sfs_fs *sfs = v->vn_fs->fs_data;
struct sfs_vnode *sv = v->vn_data;
struct sfs_vnode *newguy;
uint32_t ino;
int result;
vfs_biglock_acquire();
/* Look up the name */
result = sfs_dir_findname(sv, name, &ino, NULL, NULL);
if (result!=0 && result!=ENOENT) {
vfs_biglock_release();
return result;
}
/* If it exists and we didn't want it to, fail */
if (result==0 && excl) {
vfs_biglock_release();
return EEXIST;
}
if (result==0) {
/* We got something; load its vnode and return */
result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy);
if (result) {
vfs_biglock_release();
return result;
}
*ret = &newguy->sv_absvn;
vfs_biglock_release();
return 0;
}
/* Didn't exist - create it */
result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy);
if (result) {
vfs_biglock_release();
return result;
}
/* We don't currently support file permissions; ignore MODE */
(void)mode;
/* Link it into the directory */
result = sfs_dir_link(sv, name, newguy->sv_ino, NULL);
if (result) {
VOP_DECREF(&newguy->sv_absvn);
vfs_biglock_release();
return result;
}
/* Update the linkcount of the new file */
newguy->sv_i.sfi_linkcount++;
/* and consequently mark it dirty. */
newguy->sv_dirty = true;
*ret = &newguy->sv_absvn;
vfs_biglock_release();
return 0;
}
/*
* Make a hard link to a file.
* The VFS layer should prevent this being called unless both
* vnodes are ours.
*/
static
int
sfs_link(struct vnode *dir, const char *name, struct vnode *file)
{
struct sfs_vnode *sv = dir->vn_data;
struct sfs_vnode *f = file->vn_data;
int result;
KASSERT(file->vn_fs == dir->vn_fs);
vfs_biglock_acquire();
/* Hard links to directories aren't allowed. */
if (f->sv_i.sfi_type == SFS_TYPE_DIR) {
vfs_biglock_release();
return EINVAL;
}
/* Create the link */
result = sfs_dir_link(sv, name, f->sv_ino, NULL);
if (result) {
vfs_biglock_release();
return result;
}
/* and update the link count, marking the inode dirty */
f->sv_i.sfi_linkcount++;
f->sv_dirty = true;
vfs_biglock_release();
return 0;
}
/*
* Delete a file.
*/
static
int
sfs_remove(struct vnode *dir, const char *name)
{
struct sfs_vnode *sv = dir->vn_data;
struct sfs_vnode *victim;
int slot;
int result;
vfs_biglock_acquire();
/* Look for the file and fetch a vnode for it. */
result = sfs_lookonce(sv, name, &victim, &slot);
if (result) {
vfs_biglock_release();
return result;
}
/* Erase its directory entry. */
result = sfs_dir_unlink(sv, slot);
if (result==0) {
/* If we succeeded, decrement the link count. */
KASSERT(victim->sv_i.sfi_linkcount > 0);
victim->sv_i.sfi_linkcount--;
victim->sv_dirty = true;
}
/* Discard the reference that sfs_lookonce got us */
VOP_DECREF(&victim->sv_absvn);
vfs_biglock_release();
return result;
}
/*
* Rename a file.
*
* Since we don't support subdirectories, assumes that the two
* directories passed are the same.
*/
static
int
sfs_rename(struct vnode *d1, const char *n1,
struct vnode *d2, const char *n2)
{
struct sfs_vnode *sv = d1->vn_data;
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
struct sfs_vnode *g1;
int slot1, slot2;
int result, result2;
vfs_biglock_acquire();
KASSERT(d1==d2);
KASSERT(sv->sv_ino == SFS_ROOTDIR_INO);
/* Look up the old name of the file and get its inode and slot number*/
result = sfs_lookonce(sv, n1, &g1, &slot1);
if (result) {
vfs_biglock_release();
return result;
}
/* We don't support subdirectories */
KASSERT(g1->sv_i.sfi_type == SFS_TYPE_FILE);
/*
* Link it under the new name.
*
* We could theoretically just overwrite the original
* directory entry, except that we need to check to make sure
* the new name doesn't already exist; might as well use the
* existing link routine.
*/
result = sfs_dir_link(sv, n2, g1->sv_ino, &slot2);
if (result) {
goto puke;
}
/* Increment the link count, and mark inode dirty */
g1->sv_i.sfi_linkcount++;
g1->sv_dirty = true;
/* Unlink the old slot */
result = sfs_dir_unlink(sv, slot1);
if (result) {
goto puke_harder;
}
/*
* Decrement the link count again, and mark the inode dirty again,
* in case it's been synced behind our back.
*/
KASSERT(g1->sv_i.sfi_linkcount>0);
g1->sv_i.sfi_linkcount--;
g1->sv_dirty = true;
/* Let go of the reference to g1 */
VOP_DECREF(&g1->sv_absvn);
vfs_biglock_release();
return 0;
puke_harder:
/*
* Error recovery: try to undo what we already did
*/
result2 = sfs_dir_unlink(sv, slot2);
if (result2) {
kprintf("sfs: %s: rename: %s\n",
sfs->sfs_sb.sb_volname, strerror(result));
kprintf("sfs: %s: rename: while cleaning up: %s\n",
sfs->sfs_sb.sb_volname, strerror(result2));
panic("sfs: %s: rename: Cannot recover\n",
sfs->sfs_sb.sb_volname);
}
g1->sv_i.sfi_linkcount--;
puke:
/* Let go of the reference to g1 */
VOP_DECREF(&g1->sv_absvn);
vfs_biglock_release();
return result;
}
/*
* lookparent returns the last path component as a string and the
* directory it's in as a vnode.
*
* Since we don't support subdirectories, this is very easy -
* return the root dir and copy the path.
*/
static
int
sfs_lookparent(struct vnode *v, char *path, struct vnode **ret,
char *buf, size_t buflen)
{
struct sfs_vnode *sv = v->vn_data;
vfs_biglock_acquire();
if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
vfs_biglock_release();
return ENOTDIR;
}
if (strlen(path)+1 > buflen) {
vfs_biglock_release();
return ENAMETOOLONG;
}
strcpy(buf, path);
VOP_INCREF(&sv->sv_absvn);
*ret = &sv->sv_absvn;
vfs_biglock_release();
return 0;
}
/*
* Lookup gets a vnode for a pathname.
*
* Since we don't support subdirectories, it's easy - just look up the
* name.
*/
static
int
sfs_lookup(struct vnode *v, char *path, struct vnode **ret)
{
struct sfs_vnode *sv = v->vn_data;
struct sfs_vnode *final;
int result;
vfs_biglock_acquire();
if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
vfs_biglock_release();
return ENOTDIR;
}
result = sfs_lookonce(sv, path, &final, NULL);
if (result) {
vfs_biglock_release();
return result;
}
*ret = &final->sv_absvn;
vfs_biglock_release();
return 0;
}
////////////////////////////////////////////////////////////
// Ops tables
/*
* Function table for sfs files.
*/
const struct vnode_ops sfs_fileops = {
.vop_magic = VOP_MAGIC, /* mark this a valid vnode ops table */
.vop_eachopen = sfs_eachopen,
.vop_reclaim = sfs_reclaim,
.vop_read = sfs_read,
.vop_readlink = vopfail_uio_notdir,
.vop_getdirentry = vopfail_uio_notdir,
.vop_write = sfs_write,
.vop_ioctl = sfs_ioctl,
.vop_stat = sfs_stat,
.vop_gettype = sfs_gettype,
.vop_isseekable = sfs_isseekable,
.vop_fsync = sfs_fsync,
.vop_mmap = sfs_mmap,
.vop_truncate = sfs_truncate,
.vop_namefile = vopfail_uio_notdir,
.vop_creat = vopfail_creat_notdir,
.vop_symlink = vopfail_symlink_notdir,
.vop_mkdir = vopfail_mkdir_notdir,
.vop_link = vopfail_link_notdir,
.vop_remove = vopfail_string_notdir,
.vop_rmdir = vopfail_string_notdir,
.vop_rename = vopfail_rename_notdir,
.vop_lookup = vopfail_lookup_notdir,
.vop_lookparent = vopfail_lookparent_notdir,
};
/*
* Function table for the sfs directory.
*/
const struct vnode_ops sfs_dirops = {
.vop_magic = VOP_MAGIC, /* mark this a valid vnode ops table */
.vop_eachopen = sfs_eachopendir,
.vop_reclaim = sfs_reclaim,
.vop_read = vopfail_uio_isdir,
.vop_readlink = vopfail_uio_inval,
.vop_getdirentry = vopfail_uio_nosys,
.vop_write = vopfail_uio_isdir,
.vop_ioctl = sfs_ioctl,
.vop_stat = sfs_stat,
.vop_gettype = sfs_gettype,
.vop_isseekable = sfs_isseekable,
.vop_fsync = sfs_fsync,
.vop_mmap = vopfail_mmap_isdir,
.vop_truncate = vopfail_truncate_isdir,
.vop_namefile = sfs_namefile,
.vop_creat = sfs_creat,
.vop_symlink = vopfail_symlink_nosys,
.vop_mkdir = vopfail_mkdir_nosys,
.vop_link = sfs_link,
.vop_remove = sfs_remove,
.vop_rmdir = vopfail_string_nosys,
.vop_rename = sfs_rename,
.vop_lookup = sfs_lookup,
.vop_lookparent = sfs_lookparent,
};

81
kern/fs/sfs/sfsprivate.h Normal file
View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _SFSPRIVATE_H_
#define _SFSPRIVATE_H_
#include <uio.h> /* for uio_rw */
/* ops tables (in sfs_vnops.c) */
extern const struct vnode_ops sfs_fileops;
extern const struct vnode_ops sfs_dirops;
/* Macro for initializing a uio structure */
#define SFSUIO(iov, uio, ptr, block, rw) \
uio_kinit(iov, uio, ptr, SFS_BLOCKSIZE, ((off_t)(block))*SFS_BLOCKSIZE, rw)
/* Functions in sfs_balloc.c */
int sfs_balloc(struct sfs_fs *sfs, daddr_t *diskblock);
void sfs_bfree(struct sfs_fs *sfs, daddr_t diskblock);
int sfs_bused(struct sfs_fs *sfs, daddr_t diskblock);
/* Functions in sfs_bmap.c */
int sfs_bmap(struct sfs_vnode *sv, uint32_t fileblock, bool doalloc,
daddr_t *diskblock);
int sfs_itrunc(struct sfs_vnode *sv, off_t len);
/* Functions in sfs_dir.c */
int sfs_dir_findname(struct sfs_vnode *sv, const char *name,
uint32_t *ino, int *slot, int *emptyslot);
int sfs_dir_link(struct sfs_vnode *sv, const char *name, uint32_t ino,
int *slot);
int sfs_dir_unlink(struct sfs_vnode *sv, int slot);
int sfs_lookonce(struct sfs_vnode *sv, const char *name,
struct sfs_vnode **ret,
int *slot);
/* Functions in sfs_inode.c */
int sfs_sync_inode(struct sfs_vnode *sv);
int sfs_reclaim(struct vnode *v);
int sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int forcetype,
struct sfs_vnode **ret);
int sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret);
int sfs_getroot(struct fs *fs, struct vnode **ret);
/* Functions in sfs_io.c */
int sfs_readblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len);
int sfs_writeblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len);
int sfs_io(struct sfs_vnode *sv, struct uio *uio);
int sfs_metaio(struct sfs_vnode *sv, off_t pos, void *data, size_t len,
enum uio_rw rw);
#endif /* _SFSPRIVATE_H_ */

79
kern/gdbscripts/array Normal file
View File

@@ -0,0 +1,79 @@
# gdb scripts for dumping resizeable arrays.
#
# Unfortunately, there does not seem to be a way to do this without
# cutting and pasting for every type.
define plainarray
set $n = $arg0.num
set $i = 0
printf "%u items\n", $n
while ($i < $n)
print $arg0.v[$i]
set $i++
end
end
document plainarray
Print a plain (untyped) resizeable array.
Usage: plainarray myarray
end
define array
set $n = $arg0.arr.num
set $i = 0
printf "%u items\n", $n
while ($i < $n)
print $arg0.arr.v[$i]
set $i++
end
end
document array
Print the pointers in a typed resizeable array.
(Use plainarray for an untyped resizeable array.)
Usage: array allcpus
end
define cpuarray
set $n = $arg0.arr.num
set $i = 0
printf "%u cpus\n", $n
while ($i < $n)
printf "cpu %u:\n", $i
print *(struct cpu *)($arg0.arr.v[$i])
set $i++
end
end
document cpuarray
Print an array of struct cpu.
Usage: cpuarray allcpus
end
define threadarray
set $n = $arg0.arr.num
set $i = 0
printf "%u threads\n", $n
while ($i < $n)
printf "thread %u:\n", $i
print *(struct thread *)($arg0.arr.v[$i])
set $i++
end
end
document threadarray
Print an array of struct thread.
Usage: threadarray curproc->p_threads
end
define vnodearray
set $n = $arg0.arr.num
set $i = 0
printf "%u vnodes\n", $n
while ($i < $n)
printf "vnode %u:\n", $i
print *(struct vnode *)($arg0.arr.v[$i])
set $i++
end
end
document vnodearray
Print an array of struct vnode.
Usage: vnodearray sfs->sfs_vnodes
end

85
kern/gdbscripts/wchan Normal file
View File

@@ -0,0 +1,85 @@
# gdb scripts for manipulating wchans
define allwchans
set $n = allwchans.arr.num
set $i = 0
while ($i < $n)
set $p = (struct wchan *)(allwchans.arr.v[$i])
set $pnm = $p->wc_name
set $pth = &$p->wc_threads
set $pct = $pth->tl_count
printf "wchan %u @0x%x: %-16s %u\n", $i, $p, $pnm, $pct
set $i++
end
end
document allwchans
Dump the allwchans table.
Usage: allwchans
end
define wchan
set $p = (struct wchan *)(allwchans.arr.v[$arg0])
set $pnm = $p->wc_name
set $pth = $p->wc_threads
set $pct = $pth.tl_count
printf "wchan %u @0x%x: %-16s %u:\n", $arg0, $p, $pnm, $pct
threadlist $pth
end
document wchan
Dump a particular wchan.
Usage: wchan N
(where N is the index into allwchans[] reported by allwchans)
end
define threadlist
set $t = $arg0.tl_head.tln_next->tln_self
while ($t != 0)
printf "thread %s @0x%x\n", $t->t_name, $t
set $t = $t->t_listnode.tln_next->tln_self
end
end
document threadlist
Dump a threadlist.
Usage: threadlist mycpu->c_runqueue
end
define allcpus
set $n = allcpus.arr.num
set $i = 0
while ($i < $n)
set $c = (struct cpu *)(allcpus.arr.v[$i])
set $id = $c->c_isidle
set $ln = $c->c_spinlocks
set $t = $c->c_curthread
set $zom = $c->c_zombies.tl_count
set $rn = $c->c_runqueue.tl_count
printf "cpu %u @0x%x: ", $i, $c
if ($id)
printf "idle, "
else
printf "running, "
end
printf "%u spinlocks, ", $ln
if ($t)
printf "current: %s @0x%x\n", $t->t_name, $t
else
printf "no current thread (?)\n"
end
if ($zom > 0)
printf "%u zombies:\n", $zom
threadlist $c->c_zombies
end
if ($rn > 0)
printf "%u threads in run queue:\n", $rn
threadlist $c->c_zombies
else
printf "run queue empty\n"
end
printf "\n"
set $i++
end
end
document allcpus
Dump all cpus.
Usage: allcpus
end

132
kern/include/addrspace.h Normal file
View File

@@ -0,0 +1,132 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _ADDRSPACE_H_
#define _ADDRSPACE_H_
/*
* Address space structure and operations.
*/
#include <vm.h>
#include "opt-dumbvm.h"
struct vnode;
/*
* Address space - data structure associated with the virtual memory
* space of a process.
*
* You write this.
*/
struct addrspace {
#if OPT_DUMBVM
vaddr_t as_vbase1;
paddr_t as_pbase1;
size_t as_npages1;
vaddr_t as_vbase2;
paddr_t as_pbase2;
size_t as_npages2;
paddr_t as_stackpbase;
#else
/* Put stuff here for your VM system */
#endif
};
/*
* Functions in addrspace.c:
*
* as_create - create a new empty address space. You need to make
* sure this gets called in all the right places. You
* may find you want to change the argument list. May
* return NULL on out-of-memory error.
*
* as_copy - create a new address space that is an exact copy of
* an old one. Probably calls as_create to get a new
* empty address space and fill it in, but that's up to
* you.
*
* as_activate - make curproc's address space the one currently
* "seen" by the processor.
*
* as_deactivate - unload curproc's address space so it isn't
* currently "seen" by the processor. This is used to
* avoid potentially "seeing" it while it's being
* destroyed.
*
* as_destroy - dispose of an address space. You may need to change
* the way this works if implementing user-level threads.
*
* as_define_region - set up a region of memory within the address
* space.
*
* as_prepare_load - this is called before actually loading from an
* executable into the address space.
*
* as_complete_load - this is called when loading from an executable
* is complete.
*
* as_define_stack - set up the stack region in the address space.
* (Normally called *after* as_complete_load().) Hands
* back the initial stack pointer for the new process.
*
* Note that when using dumbvm, addrspace.c is not used and these
* functions are found in dumbvm.c.
*/
struct addrspace *as_create(void);
int as_copy(struct addrspace *src, struct addrspace **ret);
void as_activate(void);
void as_deactivate(void);
void as_destroy(struct addrspace *);
int as_define_region(struct addrspace *as,
vaddr_t vaddr, size_t sz,
int readable,
int writeable,
int executable);
int as_prepare_load(struct addrspace *as);
int as_complete_load(struct addrspace *as);
int as_define_stack(struct addrspace *as, vaddr_t *initstackptr);
/*
* Functions in loadelf.c
* load_elf - load an ELF user program executable into the current
* address space. Returns the entry point (initial PC)
* in the space pointed to by ENTRYPOINT.
*/
int load_elf(struct vnode *v, vaddr_t *entrypoint);
#endif /* _ADDRSPACE_H_ */

269
kern/include/array.h Normal file
View File

@@ -0,0 +1,269 @@
/*-
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _ARRAY_H_
#define _ARRAY_H_
#include <cdefs.h>
#include <lib.h>
#define ARRAYS_CHECKED
#ifdef ARRAYS_CHECKED
#define ARRAYASSERT KASSERT
#else
#define ARRAYASSERT(x) ((void)(x))
#endif
#ifndef ARRAYINLINE
#define ARRAYINLINE INLINE
#endif
/*
* Base array type (resizeable array of void pointers) and operations.
*
* create - allocate an array.
* destroy - destroy an allocated array.
* init - initialize an array in space externally allocated.
* cleanup - clean up an array in space externally allocated.
* num - return number of elements in array.
* get - return element no. INDEX.
* set - set element no. INDEX to VAL.
* preallocate - allocate space without changing size; may fail and
* return error.
* setsize - change size to NUM elements; may fail and return error.
* add - append VAL to end of array; return its index in INDEX_RET if
* INDEX_RET isn't null; may fail and return error.
* remove - excise entry INDEX and slide following entries down to
* close the resulting gap.
*
* Note that expanding an array with setsize doesn't initialize the new
* elements. (Usually the caller is about to store into them anyway.)
*/
struct array {
void **v;
unsigned num, max;
};
struct array *array_create(void);
void array_destroy(struct array *);
void array_init(struct array *);
void array_cleanup(struct array *);
ARRAYINLINE unsigned array_num(const struct array *);
ARRAYINLINE void *array_get(const struct array *, unsigned index);
ARRAYINLINE void array_set(const struct array *, unsigned index, void *val);
int array_preallocate(struct array *, unsigned num);
int array_setsize(struct array *, unsigned num);
ARRAYINLINE int array_add(struct array *, void *val, unsigned *index_ret);
void array_remove(struct array *, unsigned index);
/*
* Inlining for base operations
*/
ARRAYINLINE unsigned
array_num(const struct array *a)
{
return a->num;
}
ARRAYINLINE void *
array_get(const struct array *a, unsigned index)
{
ARRAYASSERT(index < a->num);
return a->v[index];
}
ARRAYINLINE void
array_set(const struct array *a, unsigned index, void *val)
{
ARRAYASSERT(index < a->num);
a->v[index] = val;
}
ARRAYINLINE int
array_add(struct array *a, void *val, unsigned *index_ret)
{
unsigned index;
int ret;
index = a->num;
ret = array_setsize(a, index+1);
if (ret) {
return ret;
}
a->v[index] = val;
if (index_ret != NULL) {
*index_ret = index;
}
return 0;
}
/*
* Bits for declaring and defining typed arrays.
*
* Usage:
*
* DECLARRAY_BYTYPE(foo, bar) declares "struct foo", which is
* an array of pointers to "bar", plus the operations on it.
*
* DECLARRAY(foo) is equivalent to DECLARRAY_BYTYPE(fooarray, struct foo).
*
* DEFARRAY_BYTYPE and DEFARRAY are the same as DECLARRAY except that
* they define the operations, and both take an extra argument INLINE.
* For C99 this should be INLINE in header files and empty in the
* master source file, the same as the usage of ARRAYINLINE above and
* in array.c.
*
* Example usage in e.g. item.h of some game:
*
* DECLARRAY_BYTYPE(stringarray, char);
* DECLARRAY(potion);
* DECLARRAY(sword);
*
* #ifndef ITEMINLINE
* #define ITEMINLINE INLINE
* #endif
*
* DEFARRAY_BYTYPE(stringarray, char, ITEMINLINE);
* DEFARRAY(potion, ITEMINLINE);
* DEFARRAY(sword, ITEMINLINE);
*
* Then item.c would do "#define ITEMINLINE" before including item.h.
*
* This creates types "struct stringarray", "struct potionarray",
* and "struct swordarray", with operations such as "swordarray_num".
*
* The operations on typed arrays are the same as the operations on
* the base array, except typed.
*/
#define DECLARRAY_BYTYPE(ARRAY, T, INLINE) \
struct ARRAY { \
struct array arr; \
}; \
\
INLINE struct ARRAY *ARRAY##_create(void); \
INLINE void ARRAY##_destroy(struct ARRAY *a); \
INLINE void ARRAY##_init(struct ARRAY *a); \
INLINE void ARRAY##_cleanup(struct ARRAY *a); \
INLINE unsigned ARRAY##_num(const struct ARRAY *a); \
INLINE T *ARRAY##_get(const struct ARRAY *a, unsigned index); \
INLINE void ARRAY##_set(struct ARRAY *a, unsigned index, T *val); \
INLINE int ARRAY##_preallocate(struct ARRAY *a, unsigned num); \
INLINE int ARRAY##_setsize(struct ARRAY *a, unsigned num); \
INLINE int ARRAY##_add(struct ARRAY *a, T *val, unsigned *index_ret); \
INLINE void ARRAY##_remove(struct ARRAY *a, unsigned index)
#define DEFARRAY_BYTYPE(ARRAY, T, INLINE) \
INLINE struct ARRAY * \
ARRAY##_create(void) \
{ \
struct ARRAY *a = kmalloc(sizeof(*a)); \
if (a == NULL) { \
return NULL; \
} \
array_init(&a->arr); \
return a; \
} \
\
INLINE void \
ARRAY##_destroy(struct ARRAY *a) \
{ \
array_cleanup(&a->arr); \
kfree(a); \
} \
\
INLINE void \
ARRAY##_init(struct ARRAY *a) \
{ \
array_init(&a->arr); \
} \
\
INLINE void \
ARRAY##_cleanup(struct ARRAY *a) \
{ \
array_cleanup(&a->arr); \
} \
\
INLINE unsigned \
ARRAY##_num(const struct ARRAY *a) \
{ \
return array_num(&a->arr); \
} \
\
INLINE T * \
ARRAY##_get(const struct ARRAY *a, unsigned index) \
{ \
return (T *)array_get(&a->arr, index); \
} \
\
INLINE void \
ARRAY##_set(struct ARRAY *a, unsigned index, T *val) \
{ \
array_set(&a->arr, index, (void *)val); \
} \
\
INLINE int \
ARRAY##_preallocate(struct ARRAY *a, unsigned num) \
{ \
return array_preallocate(&a->arr, num); \
} \
\
INLINE int \
ARRAY##_setsize(struct ARRAY *a, unsigned num) \
{ \
return array_setsize(&a->arr, num); \
} \
\
INLINE int \
ARRAY##_add(struct ARRAY *a, T *val, unsigned *index_ret) \
{ \
return array_add(&a->arr, (void *)val, index_ret); \
} \
\
INLINE void \
ARRAY##_remove(struct ARRAY *a, unsigned index) \
{ \
array_remove(&a->arr, index); \
}
#define DECLARRAY(T, INLINE) DECLARRAY_BYTYPE(T##array, struct T, INLINE)
#define DEFARRAY(T, INLINE) DEFARRAY_BYTYPE(T##array, struct T, INLINE)
/*
* This is how you declare an array of strings; it works out as
* an array of pointers to char.
*/
DECLARRAY_BYTYPE(stringarray, char, ARRAYINLINE);
DEFARRAY_BYTYPE(stringarray, char, ARRAYINLINE);
#endif /* ARRAY_H */

59
kern/include/bitmap.h Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2000, 2001
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _BITMAP_H_
#define _BITMAP_H_
/*
* Fixed-size array of bits. (Intended for storage management.)
*
* Functions:
* bitmap_create - allocate a new bitmap object.
* Returns NULL on error.
* bitmap_getdata - return pointer to raw bit data (for I/O).
* bitmap_alloc - locate a cleared bit, set it, and return its index.
* bitmap_mark - set a clear bit by its index.
* bitmap_unmark - clear a set bit by its index.
* bitmap_isset - return whether a particular bit is set or not.
* bitmap_destroy - destroy bitmap.
*/
struct bitmap; /* Opaque. */
struct bitmap *bitmap_create(unsigned nbits);
void *bitmap_getdata(struct bitmap *);
int bitmap_alloc(struct bitmap *, unsigned *index);
void bitmap_mark(struct bitmap *, unsigned index);
void bitmap_unmark(struct bitmap *, unsigned index);
int bitmap_isset(struct bitmap *, unsigned index);
void bitmap_destroy(struct bitmap *);
#endif /* _BITMAP_H_ */

141
kern/include/cdefs.h Normal file
View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 2003, 2006, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _CDEFS_H_
#define _CDEFS_H_
/*
* Some miscellaneous C language definitions and related matters.
*/
/*
* Build-time assertion. Doesn't generate any code. The error message
* on failure is less than ideal, but you can't have everything.
*/
#define COMPILE_ASSERT(x) ((void)sizeof(struct { unsigned : ((x)?1:-1); }))
/*
* Handy macro for the number of elements in a static array.
*/
#define ARRAYCOUNT(arr) (sizeof(arr) / sizeof((arr)[0]))
/*
* Tell GCC how to check printf formats. Also tell it about functions
* that don't return, as this is helpful for avoiding bogus warnings
* about uninitialized variables.
*/
#ifdef __GNUC__
#define __PF(a,b) __attribute__((__format__(__printf__, a, b)))
#define __DEAD __attribute__((__noreturn__))
#define __UNUSED __attribute__((__unused__))
#else
#define __PF(a,b)
#define __DEAD
#define __UNUSED
#endif
/*
* Material for supporting inline functions.
*
* A function marked inline can be handled by the compiler in three
* ways: in addition to possibly inlining into the code for other
* functions, the compiler can (1) generate a file-static out-of-line
* copy of the function, (2) generate a global out-of-line copy of the
* function, or (3) generate no out-of-line copy of the function.
*
* None of these alone is thoroughly satisfactory. Since an inline
* function may or may not be inlined at the compiler's discretion, if
* no out-of-line copy exists the build may fail at link time with
* undefined symbols. Meanwhile, if the compiler is told to generate a
* global out-of-line copy, it will generate one such copy for every
* source file where the inline definition is visible; since inline
* functions tend to appear in header files, this leads to multiply
* defined symbols and build failure. The file-static option isn't
* really an improvement, either: one tends to get compiler warnings
* about inline functions that haven't been used, which for any
* particular source file tends to be at least some of the ones that
* have been defined. Furthermore, this method leads to one
* out-of-line copy of the inline function per source file that uses
* it, which not only wastes space but makes debugging painful.
*
* Therefore, we use the following scheme.
*
* In the header file containing the inline functions for the module
* "foo", we put
*
* #ifndef FOO_INLINE
* #define FOO_INLINE INLINE
* #endif
*
* where INLINE selects the compiler behavior that does *not* generate
* an out-of-line version. Then we define the inline functions
* themselves as FOO_INLINE. This allows the compiler to inline the
* functions anywhere it sees fit with a minimum of hassles. Then,
* when compiling foo.c, before including headers we put
*
* #define FOO_INLINE // empty
*
* which causes the inline functions to appear as ordinary function
* definitions, not inline at all, when foo.c is compiled. This
* ensures that an out-of-line definition appears, and furthermore
* ensures that the out-of-line definition is the same as the inline
* definition.
*
* The situation is complicated further because gcc is historically
* not compliant with the C standard. In C99, "inline" means "do not
* generate an out-of-line copy" and "extern inline" means "generate a
* global out-of-line copy". In gcc, going back far longer than C99,
* the meanings were reversed. This eventually changed, but varies
* with compiler version and options. The macro __GNUC_STDC_INLINE__
* is defined if the behavior is C99-compliant.
*
* (Note that inline functions that appear only within a single source
* file can safely be declared "static inline"; to avoid whining from
* compiler in some contexts you may also want to add __UNUSED to
* that.)
*/
#if defined(__GNUC__) && !defined(__GNUC_STDC_INLINE__)
/* gcc's non-C99 inline semantics */
#define INLINE extern inline
#elif defined(__STDC__) && __STDC_VERSION__ >= 199901L
/* C99 */
#define INLINE inline
#else
/* something else; static inline is safest */
#define INLINE static __UNUSED inline
#endif
#endif /* _CDEFS_H_ */

Some files were not shown because too many files have changed in this diff Show More