Initial Spring 2016 commit.
This commit is contained in:
17
kern/Makefile
Normal file
17
kern/Makefile
Normal 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"
|
||||
79
kern/arch/mips/conf/conf.arch
Normal file
79
kern/arch/mips/conf/conf.arch
Normal 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
|
||||
98
kern/arch/mips/conf/ldscript
Normal file
98
kern/arch/mips/conf/ldscript
Normal 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) }
|
||||
}
|
||||
73
kern/arch/mips/include/current.h
Normal file
73
kern/arch/mips/include/current.h
Normal 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_ */
|
||||
58
kern/arch/mips/include/elf.h
Normal file
58
kern/arch/mips/include/elf.h
Normal 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_ */
|
||||
44
kern/arch/mips/include/kern/endian.h
Normal file
44
kern/arch/mips/include/kern/endian.h
Normal 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_ */
|
||||
74
kern/arch/mips/include/kern/regdefs.h
Normal file
74
kern/arch/mips/include/kern/regdefs.h
Normal 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_ */
|
||||
47
kern/arch/mips/include/kern/setjmp.h
Normal file
47
kern/arch/mips/include/kern/setjmp.h
Normal 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_ */
|
||||
45
kern/arch/mips/include/kern/signal.h
Normal file
45
kern/arch/mips/include/kern/signal.h
Normal 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_ */
|
||||
78
kern/arch/mips/include/kern/types.h
Normal file
78
kern/arch/mips/include/kern/types.h
Normal 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_ */
|
||||
63
kern/arch/mips/include/membar.h
Normal file
63
kern/arch/mips/include/membar.h
Normal 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_ */
|
||||
117
kern/arch/mips/include/specialreg.h
Normal file
117
kern/arch/mips/include/specialreg.h
Normal 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_ */
|
||||
122
kern/arch/mips/include/spinlock.h
Normal file
122
kern/arch/mips/include/spinlock.h
Normal 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_ */
|
||||
48
kern/arch/mips/include/thread.h
Normal file
48
kern/arch/mips/include/thread.h
Normal 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_ */
|
||||
105
kern/arch/mips/include/tlb.h
Normal file
105
kern/arch/mips/include/tlb.h
Normal 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_ */
|
||||
110
kern/arch/mips/include/trapframe.h
Normal file
110
kern/arch/mips/include/trapframe.h
Normal 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_ */
|
||||
46
kern/arch/mips/include/types.h
Normal file
46
kern/arch/mips/include/types.h
Normal 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
129
kern/arch/mips/include/vm.h
Normal 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_ */
|
||||
49
kern/arch/mips/locore/cache-mips161.S
Normal file
49
kern/arch/mips/locore/cache-mips161.S
Normal 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
|
||||
355
kern/arch/mips/locore/exception-mips1.S
Normal file
355
kern/arch/mips/locore/exception-mips1.S
Normal 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
|
||||
438
kern/arch/mips/locore/trap.c
Normal file
438
kern/arch/mips/locore/trap.c
Normal 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);
|
||||
}
|
||||
161
kern/arch/mips/syscall/syscall.c
Normal file
161
kern/arch/mips/syscall/syscall.c
Normal 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
301
kern/arch/mips/thread/cpu.c
Normal 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();
|
||||
}
|
||||
}
|
||||
99
kern/arch/mips/thread/switch.S
Normal file
99
kern/arch/mips/thread/switch.S
Normal 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
|
||||
98
kern/arch/mips/thread/switchframe.c
Normal file
98
kern/arch/mips/thread/switchframe.c
Normal 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;
|
||||
}
|
||||
52
kern/arch/mips/thread/switchframe.h
Normal file
52
kern/arch/mips/thread/switchframe.h
Normal 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_ */
|
||||
49
kern/arch/mips/thread/thread_machdep.c
Normal file
49
kern/arch/mips/thread/thread_machdep.c
Normal 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);
|
||||
}
|
||||
68
kern/arch/mips/thread/threadstart.S
Normal file
68
kern/arch/mips/thread/threadstart.S
Normal 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
433
kern/arch/mips/vm/dumbvm.c
Normal 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
153
kern/arch/mips/vm/ram.c
Normal 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;
|
||||
}
|
||||
204
kern/arch/mips/vm/tlb-mips161.S
Normal file
204
kern/arch/mips/vm/tlb-mips161.S
Normal 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
|
||||
34
kern/arch/sys161/conf/conf.arch
Normal file
34
kern/arch/sys161/conf/conf.arch
Normal 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
|
||||
334
kern/arch/sys161/dev/lamebus_machdep.c
Normal file
334
kern/arch/sys161/dev/lamebus_machdep.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
kern/arch/sys161/include/bus.h
Normal file
60
kern/arch/sys161/include/bus.h
Normal 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_ */
|
||||
44
kern/arch/sys161/include/maxcpus.h
Normal file
44
kern/arch/sys161/include/maxcpus.h
Normal 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_ */
|
||||
335
kern/arch/sys161/main/start.S
Normal file
335
kern/arch/sys161/main/start.S
Normal 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
32
kern/conf/DUMBVM
Normal 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
36
kern/conf/DUMBVM-OPT
Normal 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
33
kern/conf/GENERIC
Normal 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
36
kern/conf/GENERIC-OPT
Normal 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
440
kern/conf/conf.kern
Normal 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
1063
kern/conf/config
Executable file
File diff suppressed because it is too large
Load Diff
67
kern/conf/newvers.sh
Executable file
67
kern/conf/newvers.sh
Executable 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
71
kern/dev/generic/beep.c
Normal 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
43
kern/dev/generic/beep.h
Normal 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
397
kern/dev/generic/console.c
Normal 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);
|
||||
}
|
||||
68
kern/dev/generic/console.h
Normal file
68
kern/dev/generic/console.h
Normal 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
158
kern/dev/generic/random.c
Normal 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
46
kern/dev/generic/random.h
Normal 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_ */
|
||||
70
kern/dev/generic/rtclock.c
Normal file
70
kern/dev/generic/rtclock.c
Normal 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);
|
||||
}
|
||||
45
kern/dev/generic/rtclock.h
Normal file
45
kern/dev/generic/rtclock.h
Normal 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_ */
|
||||
55
kern/dev/lamebus/beep_ltimer.c
Normal file
55
kern/dev/lamebus/beep_ltimer.c
Normal 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;
|
||||
}
|
||||
59
kern/dev/lamebus/con_lscreen.c
Normal file
59
kern/dev/lamebus/con_lscreen.c
Normal 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;
|
||||
}
|
||||
|
||||
61
kern/dev/lamebus/con_lser.c
Normal file
61
kern/dev/lamebus/con_lser.c
Normal 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;
|
||||
}
|
||||
|
||||
57
kern/dev/lamebus/conf.lamebus
Normal file
57
kern/dev/lamebus/conf.lamebus
Normal 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
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
62
kern/dev/lamebus/emu.h
Normal 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_ */
|
||||
66
kern/dev/lamebus/emu_att.c
Normal file
66
kern/dev/lamebus/emu_att.c
Normal 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
665
kern/dev/lamebus/lamebus.c
Normal 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
182
kern/dev/lamebus/lamebus.h
Normal 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
308
kern/dev/lamebus/lhd.c
Normal 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
64
kern/dev/lamebus/lhd.h
Normal 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_ */
|
||||
69
kern/dev/lamebus/lhd_att.c
Normal file
69
kern/dev/lamebus/lhd_att.c
Normal 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
46
kern/dev/lamebus/lnet.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
52
kern/dev/lamebus/lnet_att.c
Normal file
52
kern/dev/lamebus/lnet_att.c
Normal 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;
|
||||
}
|
||||
85
kern/dev/lamebus/lrandom.c
Normal file
85
kern/dev/lamebus/lrandom.c
Normal 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;
|
||||
}
|
||||
46
kern/dev/lamebus/lrandom.h
Normal file
46
kern/dev/lamebus/lrandom.h
Normal 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_ */
|
||||
62
kern/dev/lamebus/lrandom_att.c
Normal file
62
kern/dev/lamebus/lrandom_att.c
Normal 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
225
kern/dev/lamebus/lscreen.c
Normal 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;
|
||||
}
|
||||
|
||||
59
kern/dev/lamebus/lscreen.h
Normal file
59
kern/dev/lamebus/lscreen.h
Normal 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_ */
|
||||
70
kern/dev/lamebus/lscreen_att.c
Normal file
70
kern/dev/lamebus/lscreen_att.c
Normal 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
192
kern/dev/lamebus/lser.c
Normal 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
57
kern/dev/lamebus/lser.h
Normal 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_ */
|
||||
63
kern/dev/lamebus/lser_att.c
Normal file
63
kern/dev/lamebus/lser_att.c
Normal 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
187
kern/dev/lamebus/ltimer.c
Normal 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
56
kern/dev/lamebus/ltimer.h
Normal 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_ */
|
||||
70
kern/dev/lamebus/ltimer_att.c
Normal file
70
kern/dev/lamebus/ltimer_att.c
Normal 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
116
kern/dev/lamebus/ltrace.c
Normal 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
90
kern/dev/lamebus/ltrace.h
Normal 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_ */
|
||||
69
kern/dev/lamebus/ltrace_att.c
Normal file
69
kern/dev/lamebus/ltrace_att.c
Normal 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;
|
||||
}
|
||||
57
kern/dev/lamebus/random_lrandom.c
Normal file
57
kern/dev/lamebus/random_lrandom.c
Normal 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;
|
||||
}
|
||||
66
kern/dev/lamebus/rtclock_ltimer.c
Normal file
66
kern/dev/lamebus/rtclock_ltimer.c
Normal 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
123
kern/fs/semfs/semfs.h
Normal 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
226
kern/fs/semfs/semfs_fsops.c
Normal 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
145
kern/fs/semfs/semfs_obj.c
Normal 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
799
kern/fs/semfs/semfs_vnops.c
Normal 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
103
kern/fs/sfs/sfs_balloc.c
Normal 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
303
kern/fs/sfs/sfs_bmap.c
Normal 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
239
kern/fs/sfs/sfs_dir.c
Normal 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
481
kern/fs/sfs/sfs_fsops.c
Normal 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
320
kern/fs/sfs/sfs_inode.c
Normal 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
480
kern/fs/sfs/sfs_io.c
Normal 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
650
kern/fs/sfs/sfs_vnops.c
Normal 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
81
kern/fs/sfs/sfsprivate.h
Normal 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
79
kern/gdbscripts/array
Normal 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
85
kern/gdbscripts/wchan
Normal 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
132
kern/include/addrspace.h
Normal 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
269
kern/include/array.h
Normal 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
59
kern/include/bitmap.h
Normal 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
141
kern/include/cdefs.h
Normal 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
Reference in New Issue
Block a user