From 5cf3960140d6de7855d5846beac6b80105b719e0 Mon Sep 17 00:00:00 2001 From: Josef Jeff Sipek Date: Sat, 6 Oct 2007 15:25:09 -0400 Subject: [PATCH] Import source --- .hgignore | 8 + COPYING | 348 +++++++++++++++++++++++++++++++++++++++ Documentation/ipl.txt | 80 +++++++++ Documentation/memory.txt | 62 +++++++ Makefile | 91 ++++++++++ hercules/hvf.cnf | 29 ++++ hercules/tape-hvf.tdf | 4 + include/atomic.h | 203 +++++++++++++++++++++++ include/binfmt_elf.h | 95 +++++++++++ include/buddy.h | 10 ++ include/channel.h | 120 ++++++++++++++ include/compiler.h | 10 ++ include/config.h | 6 + include/errno.h | 11 ++ include/interrupt.h | 16 ++ include/io.h | 40 +++++ include/list.h | 421 +++++++++++++++++++++++++++++++++++++++++++++++ include/mm.h | 6 + include/nucleus.h | 46 ++++++ include/page.h | 47 ++++++ include/sched.h | 6 + include/slab.h | 17 ++ include/types.h | 24 +++ ipl/ipl.S_in | 133 +++++++++++++++ ipl/linker.script | 9 + ipl/loader.c | 328 ++++++++++++++++++++++++++++++++++++ ipl/loader_asm.S | 208 +++++++++++++++++++++++ ipl/setmode.S | 47 ++++++ lib/Makefile | 1 + lib/string.c | 34 ++++ lib/vsprintf.c | 391 +++++++++++++++++++++++++++++++++++++++++++ linker.script | 8 + mm/Makefile | 1 + mm/buddy.c | 132 +++++++++++++++ mm/page.c | 32 ++++ mm/slab.c | 175 ++++++++++++++++++++ nucleus/Makefile | 1 + nucleus/init.c | 79 +++++++++ nucleus/io.c | 135 +++++++++++++++ nucleus/printf.c | 28 ++++ scripts/gen_ipl_s.sh | 28 ++++ 41 files changed, 3470 insertions(+) create mode 100644 .hgignore create mode 100644 COPYING create mode 100644 Documentation/ipl.txt create mode 100644 Documentation/memory.txt create mode 100644 Makefile create mode 100644 hercules/hvf.cnf create mode 100644 hercules/tape-hvf.tdf create mode 100644 include/atomic.h create mode 100644 include/binfmt_elf.h create mode 100644 include/buddy.h create mode 100644 include/channel.h create mode 100644 include/compiler.h create mode 100644 include/config.h create mode 100644 include/errno.h create mode 100644 include/interrupt.h create mode 100644 include/io.h create mode 100644 include/list.h create mode 100644 include/mm.h create mode 100644 include/nucleus.h create mode 100644 include/page.h create mode 100644 include/sched.h create mode 100644 include/slab.h create mode 100644 include/types.h create mode 100644 ipl/ipl.S_in create mode 100644 ipl/linker.script create mode 100644 ipl/loader.c create mode 100644 ipl/loader_asm.S create mode 100644 ipl/setmode.S create mode 100644 lib/Makefile create mode 100644 lib/string.c create mode 100644 lib/vsprintf.c create mode 100644 linker.script create mode 100644 mm/Makefile create mode 100644 mm/buddy.c create mode 100644 mm/page.c create mode 100644 mm/slab.c create mode 100644 nucleus/Makefile create mode 100644 nucleus/init.c create mode 100644 nucleus/io.c create mode 100644 nucleus/printf.c create mode 100755 scripts/gen_ipl_s.sh diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000..993b4e7 --- /dev/null +++ b/.hgignore @@ -0,0 +1,8 @@ +\.o$ +\.rto$ +^ipl/ipl\.S$ +^hvf$ +^ipl/\. +^loader\.bin$ +^cscope\.out$ +\.swp$ diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d48d160 --- /dev/null +++ b/COPYING @@ -0,0 +1,348 @@ + Note that the only valid version of the GPL as far as the kernel is + concerned is _this_ particular version of the license (ie v2, not v2.2 + or v3.x or whatever), unless explicitly otherwise stated. + + Josef 'Jeff' Sipek. + +---------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Documentation/ipl.txt b/Documentation/ipl.txt new file mode 100644 index 0000000..83e6ee6 --- /dev/null +++ b/Documentation/ipl.txt @@ -0,0 +1,80 @@ +This file attempts to describe what happens during IPL. + +NOTE: At the time, only IPL from tape is supported. + +1) system reads 24 bytes from the device + + a) bytes 0-7: new PSW, no interrupts, start address 0x800000 (8MB) + + b) bytes 8-15: CCW to rewind the tape to previous TM + + c) bytes 16-23: CCW to read the entire loader to 0x800000 (8 MB) + +2) arch mode is changed to z/Arch (see ipl/setmode.S) + +3) temporary stack is set up (R15 being the pointer) (see ipl/setmode.S) + +4) loader begins to execute: function load_nucleus (see ipl/loader.c) + + NOTE: loader.c use static inlines extensively, and thefore stack usage is + minimal + + a) nucleus is read from tape to 0x400000 (4 MB) + + NOTE: the data at 4MB just read is an 64-bit s390 ELF binary with + Linux ABI bits + + i) addition CCW address is set in the ORB + + ii) __readnucleus() is called; this function is implemented in + assembly (see ipl/loader_asm.S) + + iii) IO interrupt handler is set up (implemented in asm, see + ipl/loader_asm.S) + + iv) ORB is sent to the subchannel + + v) interrupts are enabled + + vi) a new PSW with wait state bit set is loaded + + vii) on IO interrupt + + 1) TSCH is issued to fill in a IRB + + 2) magic value (ORB int param) is checked + + 3) Device End flag is checked in the IRB + + NOTE: more checks should be performed here + + 4) If the device end flag is set, return to code that set up the + interrupt handler + + 5) otherwise, load up the old IO PSW (the one with the wait + state) + + viii)return to caller (back to ipl/loader.c) + + b) verify ELF header magic number, machine, type, etc. values + + c) traverse the section headers & copy data to final destination + + i) if the section type is PROGBITS (data stored in the ELF), copy + the data from it's temporary location to the desired location + (destination, offset within file, and length are all stored in + the section header) - this takes care of .text, .data, and + .rodata sections + + ii) if the section type is NOBITS (uninitialized storage, e.g., + .bss), do nothing, just assume that the location is a valid + location in memory + + iii) skip any other section types + + NOTE: SYMTAB and STRTAB section types should be copied to a useful + location to allow for symbols to be looked up during nucleus execution + + d) jump to the entry point as indicated by the ELF header + +At this point, the nucleus is executing. diff --git a/Documentation/memory.txt b/Documentation/memory.txt new file mode 100644 index 0000000..94458a5 --- /dev/null +++ b/Documentation/memory.txt @@ -0,0 +1,62 @@ +Physical locations: + +------------------- (2^64)-1 -- +| | \ +| | | + . | + . \ + . > Generic pages + . / + . | +| | | +| | / +|-----------------| f(memsize)-- +| | \ +| | | + . \ + . > struct page array (see below) + . / +| | | +| | / +|-----------------| 4M -- +| | \ +| | | + . \ + . > OS .text, .data, .rodata, .bss + . / +| | | +| | / +|-----------------| 1M -- +| | \ +| | | + . | + . | + . \ +| | > PSA for each CPU +| | / +|-----------------| 8k | +| | | +| PSA | | +| | / +------------------- 0 -- + + +0 - 1MB: + Divided into up to 128 8KB chunks; nth chunk is nth CPU's PSA + (mapping done via the prefix register). + +1MB - 4MB: + OS .text + OS .data + OS .rodata + OS .bss + +4MB - (4MB + roundup((memsize >> PAGE_SIZE) * sizeof(struct page))): + This is an array of struct page entries for each page in the system. + The size varies based on the amount of memory installed. + +?? - (2^64)-1: + Generic pages; used for nucleus & process data + + These pages are managed by the buddy allocator. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6e9cfb2 --- /dev/null +++ b/Makefile @@ -0,0 +1,91 @@ +# +# HVF: Hobbyist Virtualization Facility +# + +VERSION=0.10 + +AS=as +CC=gcc +LD=ld +OBJCOPY=objcopy + +MAKEFLAGS += -rR --no-print-directory +CFLAGS=-g -fno-builtin -nostdinc -nostdlib -Wall -m64 -I include/ -O2 +NUCLEUSCFLAGS=-include include/nucleus.h +LDFLAGS=-m elf64_s390 + +.PRECIOUS: %.o + +.PHONY: all build clean cleanup hvfclean iplclean + +ifneq ($(DIR),) +.PHONY: $(DIR) +override DIR:=$(subst /,,$(DIR)) +endif + +TOP_DIRS=nucleus/ mm/ lib/ + +all: + @$(MAKE) DIR=nucleus/ build + @$(MAKE) DIR=mm/ build + @$(MAKE) DIR=lib/ build + @$(MAKE) hvf + @$(MAKE) ipl/ + +hvf: $(patsubst %/,%/built-in.o,$(TOP_DIRS)) + $(LD) $(LDFLAGS) -T linker.script -o $@ $^ + +clean: + @$(MAKE) DIR=nucleus/ cleanup + @$(MAKE) DIR=mm/ cleanup + @$(MAKE) DIR=lib/ cleanup + rm -f hvf + rm -f loader.bin ipl/*.o ipl/*.rto ipl/.*.o ipl/ipl.S + rm -f cscope.out ctags + +cleanup: + rm -f $(DIR)/*.o + +build: $(DIR)/built-in.o + +# +# Include Makefiles from all the top level directories +# +include $(patsubst %/,%/Makefile,$(TOP_DIRS)) + +%/built-in.o: $(patsubst %,$(DIR)/%,$(objs-$(DIR))) + $(LD) $(LDFLAGS) -r -o $@ $(patsubst %,$(DIR)/%,$(objs-$(DIR))) + +%.o: %.c + $(CC) $(CFLAGS) $(NUCLEUSCFLAGS) -c -o $@ $< + + +# +# IPL specific bits +# + +.PRECIOUS: ipl/%.o + +ipl/: loader.bin + +loader.bin: ipl/ipl.rto ipl/setmode.rto ipl/loader.rto + cat ipl/ipl.rto > "$@" + cat ipl/setmode.rto >> "$@" + cat ipl/loader.rto >> "$@" + +ipl/%.rto: ipl/%.o + $(OBJCOPY) -O binary -j .text $< $@ + +ipl/%.o: ipl/%.S + $(AS) -m31 -o $@ $< + +ipl/ipl.S: ipl/ipl.S_in ipl/setmode.rto ipl/loader.rto scripts/gen_ipl_s.sh + bash scripts/gen_ipl_s.sh "$<" "$@" + +ipl/loader.rto: ipl/loader.o + $(OBJCOPY) -O binary -j .text -j .data -j .rodata $< $@ + +ipl/loader.o: ipl/loader.c ipl/loader_asm.S hvf + $(AS) -m64 -o ipl/.loader_asm.o ipl/loader_asm.S + $(CC) $(CFLAGS) -DBLOCK_SIZE=4096 -DBYTES_TO_READ=`stat -c %s hvf` -c -o ipl/.loader.o ipl/loader.c + $(LD) -melf64_s390 -o $@ -T ipl/linker.script ipl/.loader.o ipl/.loader_asm.o diff --git a/hercules/hvf.cnf b/hercules/hvf.cnf new file mode 100644 index 0000000..6715584 --- /dev/null +++ b/hercules/hvf.cnf @@ -0,0 +1,29 @@ +# +# Sample configuration file for Hercules zArch emulator +# + +CPUSERIAL 000777 # CPU serial number +CPUMODEL 3158 # CPU model number +MAINSIZE 256 # Main storage size in megabytes +XPNDSIZE 0 # Expanded storage size in megabytes +CNSLPORT 3271 # TCP port number to which consoles connect +NUMCPU 1 # Number of CPUs +LOADPARM 0120.... # IPL parameter +OSTAILOR VM # OS tailoring +PANRATE SLOW # Panel refresh rate +ARCHMODE ESAME + +# .-----------------------Device number +# | .-----------------Device type +# | | .---------File name and parameters +# | | | +# V V V +#--- ---- -------------------- +0009 3270 +000C 3505 +000D 3525 punch00d.txt ascii +000E 1403 print00e.txt crlf +001F 3215 +0040 3270 +0041 3270 +0580 3420 tape-hvf.tdf diff --git a/hercules/tape-hvf.tdf b/hercules/tape-hvf.tdf new file mode 100644 index 0000000..76f7156 --- /dev/null +++ b/hercules/tape-hvf.tdf @@ -0,0 +1,4 @@ +@TDF +/home/jeffpc/hvf/loader.bin FIXED RECSIZE 1024 +/home/jeffpc/hvf/hvf FIXED RECSIZE 4096 +EOT diff --git a/include/atomic.h b/include/atomic.h new file mode 100644 index 0000000..92252cf --- /dev/null +++ b/include/atomic.h @@ -0,0 +1,203 @@ +/* + * Based on atomic.h from Linux Kernel + */ + +#ifndef __ARCH_S390_ATOMIC__ +#define __ARCH_S390_ATOMIC__ + +/* + * include/asm-s390/atomic.h + * + * S390 version + * Copyright (C) 1999-2005 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * Denis Joseph Barrow, + * Arnd Bergmann (arndb@de.ibm.com) + * + * Derived from "include/asm-i386/bitops.h" + * Copyright (C) 1992, Linus Torvalds + * + */ + +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + * S390 uses 'Compare And Swap' for atomicity in SMP enviroment + */ + +typedef struct { + volatile int counter; +} __attribute__ ((aligned (4))) atomic_t; +#define ATOMIC_INIT(i) { (i) } + +#define __CS_LOOP(ptr, op_val, op_string) ({ \ + typeof(ptr->counter) old_val, new_val; \ + asm volatile( \ + " l %0,%2\n" \ + "0: lr %1,%0\n" \ + op_string " %1,%3\n" \ + " cs %0,%1,%2\n" \ + " jl 0b" \ + : "=&d" (old_val), "=&d" (new_val), \ + "=Q" (((atomic_t *)(ptr))->counter) \ + : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \ + : "cc", "memory"); \ + new_val; \ +}) + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) + +static __inline__ int atomic_add_return(int i, atomic_t * v) +{ + return __CS_LOOP(v, i, "ar"); +} +#define atomic_add(_i, _v) atomic_add_return(_i, _v) +#define atomic_add_negative(_i, _v) (atomic_add_return(_i, _v) < 0) +#define atomic_inc(_v) atomic_add_return(1, _v) +#define atomic_inc_return(_v) atomic_add_return(1, _v) +#define atomic_inc_and_test(_v) (atomic_add_return(1, _v) == 0) + +static __inline__ int atomic_sub_return(int i, atomic_t * v) +{ + return __CS_LOOP(v, i, "sr"); +} +#define atomic_sub(_i, _v) atomic_sub_return(_i, _v) +#define atomic_sub_and_test(_i, _v) (atomic_sub_return(_i, _v) == 0) +#define atomic_dec(_v) atomic_sub_return(1, _v) +#define atomic_dec_return(_v) atomic_sub_return(1, _v) +#define atomic_dec_and_test(_v) (atomic_sub_return(1, _v) == 0) + +static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t * v) +{ + __CS_LOOP(v, ~mask, "nr"); +} + +static __inline__ void atomic_set_mask(unsigned long mask, atomic_t * v) +{ + __CS_LOOP(v, mask, "or"); +} + +#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) + +static __inline__ int atomic_cmpxchg(atomic_t *v, int old, int new) +{ + asm volatile( + " cs %0,%2,%1" + : "+d" (old), "=Q" (v->counter) + : "d" (new), "Q" (v->counter) + : "cc", "memory"); + return old; +} + +static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) +{ + int c, old; + c = atomic_read(v); + for (;;) { + if (unlikely(c == u)) + break; + old = atomic_cmpxchg(v, c, c + a); + if (likely(old == c)) + break; + c = old; + } + return c != u; +} + +#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) + +#undef __CS_LOOP + +typedef struct { + volatile long long counter; +} __attribute__ ((aligned (8))) atomic64_t; +#define ATOMIC64_INIT(i) { (i) } + +#define __CSG_LOOP(ptr, op_val, op_string) ({ \ + typeof(ptr->counter) old_val, new_val; \ + asm volatile( \ + " lg %0,%2\n" \ + "0: lgr %1,%0\n" \ + op_string " %1,%3\n" \ + " csg %0,%1,%2\n" \ + " jl 0b" \ + : "=&d" (old_val), "=&d" (new_val), \ + "=Q" (((atomic_t *)(ptr))->counter) \ + : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \ + : "cc", "memory" ); \ + new_val; \ +}) + +#define atomic64_read(v) ((v)->counter) +#define atomic64_set(v,i) (((v)->counter) = (i)) + +static __inline__ long long atomic64_add_return(long long i, atomic64_t * v) +{ + return __CSG_LOOP(v, i, "agr"); +} +#define atomic64_add(_i, _v) atomic64_add_return(_i, _v) +#define atomic64_add_negative(_i, _v) (atomic64_add_return(_i, _v) < 0) +#define atomic64_inc(_v) atomic64_add_return(1, _v) +#define atomic64_inc_return(_v) atomic64_add_return(1, _v) +#define atomic64_inc_and_test(_v) (atomic64_add_return(1, _v) == 0) + +static __inline__ long long atomic64_sub_return(long long i, atomic64_t * v) +{ + return __CSG_LOOP(v, i, "sgr"); +} +#define atomic64_sub(_i, _v) atomic64_sub_return(_i, _v) +#define atomic64_sub_and_test(_i, _v) (atomic64_sub_return(_i, _v) == 0) +#define atomic64_dec(_v) atomic64_sub_return(1, _v) +#define atomic64_dec_return(_v) atomic64_sub_return(1, _v) +#define atomic64_dec_and_test(_v) (atomic64_sub_return(1, _v) == 0) + +static __inline__ void atomic64_clear_mask(unsigned long mask, atomic64_t * v) +{ + __CSG_LOOP(v, ~mask, "ngr"); +} + +static __inline__ void atomic64_set_mask(unsigned long mask, atomic64_t * v) +{ + __CSG_LOOP(v, mask, "ogr"); +} + +#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) + +static __inline__ long long atomic64_cmpxchg(atomic64_t *v, + long long old, long long new) +{ + asm volatile( + " csg %0,%2,%1" + : "+d" (old), "=Q" (v->counter) + : "d" (new), "Q" (v->counter) + : "cc", "memory"); + return old; +} + +static __inline__ int atomic64_add_unless(atomic64_t *v, + long long a, long long u) +{ + long long c, old; + c = atomic64_read(v); + for (;;) { + if (unlikely(c == u)) + break; + old = atomic64_cmpxchg(v, c, c + a); + if (likely(old == c)) + break; + c = old; + } + return c != u; +} + +#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) + +#undef __CSG_LOOP + +#define smp_mb__before_atomic_dec() smp_mb() +#define smp_mb__after_atomic_dec() smp_mb() +#define smp_mb__before_atomic_inc() smp_mb() +#define smp_mb__after_atomic_inc() smp_mb() + +#endif /* __ARCH_S390_ATOMIC__ */ diff --git a/include/binfmt_elf.h b/include/binfmt_elf.h new file mode 100644 index 0000000..525cc43 --- /dev/null +++ b/include/binfmt_elf.h @@ -0,0 +1,95 @@ +#ifndef __BINFMT_ELF_H +#define __BINFMT_ELF_H + +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_ABIVERSION 8 +#define EI_PAD 9 +#define EI_NIDENT 16 + +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_CURRENT 1 + +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOOS 0xfe00 +#define ET_HIOS 0xfeff +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOOS 0x60000000 +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff + +typedef u64 Elf64_Addr; +typedef u64 Elf64_Off; +typedef u16 Elf64_Half; +typedef u32 Elf64_Word; +typedef s32 Elf64_Sword; +typedef u64 Elf64_Xword; +typedef s64 Elf64_Sxword; + +/* + * ELF file header + */ +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF identification */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Machine type */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point address */ + Elf64_Off e_phoff; /* Program header offset */ + Elf64_Off e_shoff; /* Section header offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size */ + Elf64_Half e_phentsize; /* Size of program header entry */ + Elf64_Half e_phnum; /* Number of program header entries */ + Elf64_Half e_shentsize; /* Size of section header entries */ + Elf64_Half e_shnum; /* Number of section header entries */ + Elf64_Half e_shstrndx; /* Section name string table index */ +} Elf64_Ehdr; + +/* + * ELF section header + */ +typedef struct { + Elf64_Word sh_name; /* Section name */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section attributes */ + Elf64_Addr sh_addr; /* Virtual address in memory */ + Elf64_Off sh_offset; /* Offset in file */ + Elf64_Xword sh_size; /* Size of section */ + Elf64_Word sh_link; /* Link to other section */ + Elf64_Word sh_info; /* Misc information */ + Elf64_Xword sh_addralign; /* Address alignment boundary */ + Elf64_Xword sh_entsize; /* Size of entries, if section has table */ +} Elf64_Shdr; + +#endif diff --git a/include/buddy.h b/include/buddy.h new file mode 100644 index 0000000..02d1fd3 --- /dev/null +++ b/include/buddy.h @@ -0,0 +1,10 @@ +#ifndef __BUDDY_H +#define __BUDDY_H + +#include + +extern void init_buddy_alloc(u64 start); +extern struct page *alloc_pages(int order); +extern void free_pages(void *ptr, int order); + +#endif diff --git a/include/channel.h b/include/channel.h new file mode 100644 index 0000000..73d3b11 --- /dev/null +++ b/include/channel.h @@ -0,0 +1,120 @@ +#ifndef __CHANNEL_H +#define __CHANNEL_H + +/* + * We only care about format-1 CCWs + */ +struct ccw { + u8 cmd; /* command code */ + struct { + u8 cd:1, /* Chain-Data */ + cc:1, /* Chain-Command */ + sli:1, /* Suppress-Length-Indication */ + skp:1, /* Skip */ + pci:1, /* Program-Controlled-Interruption */ + ida:1, /* Indirect-Data-Address */ + s:1, /* Suspend */ + mida:1; /* Modified-Indirect-Data-Address */ + } flags; + u16 count; /* Count */ + u32 addr; /* Data Address */ +} __attribute__((packed,aligned(8))); + +/* + * ORB + */ +struct orb { + /* word 0 */ + u32 param; /* Interruption Parameter */ + + /* word 1 */ + u16 key:8, /* Subchannel Key */ + s:1, /* Suspend */ + c:1, /* Streaming-Mode Control */ + m:1, /* Modification Control */ + y:1, /* Synchronization Control */ + f:1, /* Format Control */ + p:1, /* Prefetch Control */ + i:1, /* Initial-Status-Interruption Control */ + a:1, /* Address-Limit-Checking control */ + u:1, /* Suppress-Suspend-Interruption Control */ + __zero1:1, + h:1, /* Format-2-IDAW Control */ + t:1; /* 2K-IDAW Control */ + u16 lpm:8, /* Logical-Path Mask */ + l:1, /* Incorrect-Length-Suppression Mode */ + d:1, /* Modified-CCW-Indirect-Data-Addressing Control */ + __zero2:5, + x:1; /* ORB-Extension Control */ + + /* word 2 */ + u32 addr; /* Channel-Program Address */ + + /* word 3 */ + u8 css_prio; /* Channel-Subsystem Priority */ + u8 __reserved1; + u8 cu_prio; /* Control-Unit Priority */ + u8 __reserved2; + + /* word 4 - 7 */ + u32 __reserved3; + u32 __reserved4; + u32 __reserved5; + u32 __reserved6; +} __attribute__((packed,aligned(4))); + +/* part of IRB */ +struct irb_subch_status { + /* word 0 */ + u16 key:4, /* Subchannel key */ + s:1, /* Suspend control */ + l:1, /* ESW format */ + cc:2, /* Deferred condition code */ + f:1, /* Format */ + p:1, /* Prefetch */ + i:1, /* Initial-status interruption control */ + a:1, /* Address-limit-checking control */ + u:1, /* Supress-suspended interruption */ + z:1, /* Zero condition code */ + e:1, /* Extended control */ + n:1; /* Path no operational */ + u16 __zero:1, + fc:3, /* Function control */ + ac:8, /* Activity control */ + sc:4; /* Status control */ + + /* word 1 */ + u32 addr; /* CCW Address */ + + /* word 2 */ + u8 dev_status; /* Device status */ + u8 sch_status; /* Subchannel status */ + u16 count; /* Count */ +} __attribute__((packed)); + +/* needed by IRB */ +struct irb_ext_status { + /* TODO: not implemented */ + u32 w0, w1, w2, w3, w4; +} __attribute__((packed)); + +/* needed by IRB */ +struct irb_ext_control { + /* TODO: not implemented */ + u32 w0, w1, w2, w3, w4, w5, w6, w7; +} __attribute__((packed)); + +/* needed by IRB */ +struct irb_ext_measurement { + /* TODO: not implemented */ + u32 w0, w1, w2, w3, w4, w5, w6, w7; +} __attribute__((packed)); + +struct irb { + struct irb_subch_status status; /* Subchannel-Status */ + struct irb_ext_status ext_status; /* Extended-Status */ + struct irb_ext_control ext_control; /* Extended-Control */ + struct irb_ext_measurement ext_measure; /* Extended-Measurement */ +} __attribute__((packed,aligned(4))); + +#endif diff --git a/include/compiler.h b/include/compiler.h new file mode 100644 index 0000000..ad81e29 --- /dev/null +++ b/include/compiler.h @@ -0,0 +1,10 @@ +#ifndef __COMPILER_H +#define __COMPILER_H + +/* + * For compatibility with some Linux kernel code + */ +#define likely(x) (x) +#define unlikely(x) (x) + +#endif diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..6355f72 --- /dev/null +++ b/include/config.h @@ -0,0 +1,6 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#define MEMSIZE (1024*1024*256) + +#endif diff --git a/include/errno.h b/include/errno.h new file mode 100644 index 0000000..7f1ea4f --- /dev/null +++ b/include/errno.h @@ -0,0 +1,11 @@ +#ifndef __ERRNO_H +#define __ERRNO_H + +#define ENOMEM 1 +#define EBUSY 2 +#define EAGAIN 3 + +#define PTR_ERR(ptr) ((s64) ptr) +#define ERR_PTR(err) ((void*) err) + +#endif diff --git a/include/interrupt.h b/include/interrupt.h new file mode 100644 index 0000000..dbe9edb --- /dev/null +++ b/include/interrupt.h @@ -0,0 +1,16 @@ +#ifndef __INTERRUPT_H +#define __INTERRUPT_H + +/* + * I/O interruptions specific constants & structures + */ +struct io_int_code { + u32 ssid; + u32 param; +} __attribute__((packed)); + +#define IO_INT_OLD_PSW ((void*) 368) +#define IO_INT_NEW_PSW ((void*) 496) +#define IO_INT_CODE ((struct io_int_code*) 184) + +#endif diff --git a/include/io.h b/include/io.h new file mode 100644 index 0000000..5b5f38f --- /dev/null +++ b/include/io.h @@ -0,0 +1,40 @@ +#ifndef __IO_H +#define __IO_H + +#include +#include + +/* + * Defines an I/O operation + * + * This structure contains any and all state one should need to service any + * I/O interruption. + */ +struct io_op { + struct orb orb; /* Operation Request Block */ + + int (*handler)(struct io_op *ioop, struct irb *irb); + /* I/O specific callback */ + + int ssid; /* subsystem ID */ + + int err; /* return code */ + int done; /* has the operation completed */ +}; + +/* + * This is an ugly hack to avoid having to lock the entire in-flight ops + * array; instead, we scan the list linearly, until we find an unused + * io_op_inflight_entry. + */ +struct io_op_inflight_entry { + struct io_op *op; + atomic_t used; +}; + +#define MAX_IOS 128 /* max number of in-flight IO ops */ + +extern void init_io(); +extern int submit_io(struct io_op *oop, int flags); + +#endif diff --git a/include/list.h b/include/list.h new file mode 100644 index 0000000..3202369 --- /dev/null +++ b/include/list.h @@ -0,0 +1,421 @@ +/* + * Based on list.h from Linux Kernel + */ + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#define LIST_POISON1 ((void*) 0x8585858585858585) +#define LIST_POISON2 ((void*) 0x8686868686868686) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +#endif diff --git a/include/mm.h b/include/mm.h new file mode 100644 index 0000000..375942d --- /dev/null +++ b/include/mm.h @@ -0,0 +1,6 @@ +#ifndef __MM_H +#define __MM_H + +extern u64 memsize; + +#endif diff --git a/include/nucleus.h b/include/nucleus.h new file mode 100644 index 0000000..e223325 --- /dev/null +++ b/include/nucleus.h @@ -0,0 +1,46 @@ +#ifndef __NUCLEUS_H +#define __NUCLEUS_H + +#include +#include +#include +#include + +/* borrowed from Linux */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* borrowed from Linux */ +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#define BUG() do { } while(0) +#define BUG_ON(cond) do { \ + if (unlikely(cond)) \ + BUG(); \ + } while(0) + +/* + * string.h equivalents + */ +extern void *memset(void *s, int c, size_t n); +extern void *memcpy(void *dst, void *src, int len); +extern int strnlen(const char *s, size_t maxlen); + +/* + * stdio.h equivalents + */ +extern int vprintf(const char *fmt, va_list args) + __attribute__ ((format (printf, 1, 0))); +extern int printf(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); +extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); + +/* + * stdarg.h equivalents + */ +#define va_start(ap, last) __builtin_va_start(ap, last) +#define va_arg(ap, type) __builtin_va_arg(ap, type) +#define va_end(ap) __builtin_va_end(ap) + +#endif diff --git a/include/page.h b/include/page.h new file mode 100644 index 0000000..12da12d --- /dev/null +++ b/include/page.h @@ -0,0 +1,47 @@ +#ifndef __PAGE_H +#define __PAGE_H + +#include + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1<> PAGE_SHIFT]; +} + +#endif diff --git a/include/sched.h b/include/sched.h new file mode 100644 index 0000000..ea3ec1a --- /dev/null +++ b/include/sched.h @@ -0,0 +1,6 @@ +#ifndef __SCHED_H +#define __SCHED_H + +#define SCHED_CANSLEEP 1 /* safe to sleep */ + +#endif diff --git a/include/slab.h b/include/slab.h new file mode 100644 index 0000000..8cb0e65 --- /dev/null +++ b/include/slab.h @@ -0,0 +1,17 @@ +#ifndef __SLAB_H +#define __SLAB_H + +struct slab { + struct slab *next; + u16 objsize; + u16 count; + u16 used; + u16 startoff; +} __attribute((packed))__; + +extern int init_slab(); + +extern struct slab *create_slab(u16 objsize); +extern void free_slab(struct slab *slab); + +#endif diff --git a/include/types.h b/include/types.h new file mode 100644 index 0000000..029a5f1 --- /dev/null +++ b/include/types.h @@ -0,0 +1,24 @@ +#ifndef __TYPES_H +#define __TYPES_H + +#define NULL ((void*) 0) + +typedef unsigned long u64; +typedef signed long s64; + +typedef unsigned int u32; +typedef signed int s32; + +typedef unsigned short u16; +typedef signed short s16; + +typedef unsigned char u8; +typedef signed char s8; + +typedef u32 size_t; + +typedef __builtin_va_list va_list; + +typedef int ptrdiff_t; /* wha? well, vsnprintf wants it */ + +#endif diff --git a/ipl/ipl.S_in b/ipl/ipl.S_in new file mode 100644 index 0000000..902a006 --- /dev/null +++ b/ipl/ipl.S_in @@ -0,0 +1,133 @@ +# During the system IPL, 24 bytes are read from the device. +# +# NOTE: zArch IPLs in ESA/390 mode. +# + +# +# Bytes 0-7 contain PSW to be loaded after IO operation completes +# + .byte 0x00 + # bits value name desc + # 0 0 + # 1 0 PER Mask (R) disabled + # 2-4 0 + # 5 0 DAT Mode (T) disabled + # 6 0 I/O Mask (IO) disabled + # 7 0 External Mask (EX) disabled + + .byte 0x0c + # bits value name desc + # 8-11 0 Key + # 12 1 + # 13 1 Machine-Check Mask (M) enabled + # 14 0 Wait State (W) executing + # 15 0 Problem State (P) supervisor state + + .byte 0x00 + # bits value name desc + # 16-17 0 Address-Space Control (AS) disabled + # 18-19 0 Condition Code (CC) + # 20-23 0 Program Mask exceptions disabled + + .byte 0x00 + # bits value name desc + # 24-30 0 + # 31 1 Extended Addressing (EA) EA + BA = 64 mode + + .byte 0x80 # bits 32-39 + .byte 0x80 # bits 40-47 + .byte 0x00 # bits 48-55 + .byte 0x00 # bits 56-63 + # bits value name desc + # 32 1 Basic Addressing (BA) BA = 31, !BA = 24 + # 33-63 addr Instruction Address Address to exec + +# +# The remaining 16 bytes should contain CCW to read data from device +# + +# +# The following is a little bit subtle... +# +# CCW 1 loads (( CCW1H << 16 ) + CCW1L ) bytes to 0x800000 (command chain) +# CCW 2 loads (( CCW2H << 16 ) + CCW2L ) bytes to +# 0x800000 + (( CCW1H << 16 ) + CCW1L ) (no command chain) +# + +# +# CCW 1 (bytes 8-15): format-0 +# + .byte 0x27 + # bits value name desc + # 0-7 2 Cmd Code ?, modifiers + + .byte 0x00 + .byte 0x00 + .byte 0x00 + # bits value name desc + # 8-31 addr Data Address dest of the read + + .byte 0x60 + # bits value name desc + # 32 0 Chain-Data (CD) don't chain + # 33 1 Chain-Command (CC) read more + # 34 1 Sup.-Len.-Inditcation (SLI) suppress + # 35 0 Skip (SKP) issue read + # 36 0 Prog.-Contr.-Inter. (PCI) don't interrupt + # 37 0 Indir.-Data-Addr. (IDA) real addr + # 38 0 Suspend (S) don't suspend + # 39 0 Modified I.D.A. (MIDA) real addr + + .byte 0x00 + # bits value name desc + # 40-47 0 + + .byte 0x00 + .byte 0x01 + # bits value name desc + # 48-63 len number of bytes to read + +# +# CCW 2 (bytes 16-23): format-0 +# + .byte 0x02 + # bits value name desc + # 0-7 2 Cmd Code read, no modifiers + + .byte 0x7f + .byte 0xff + .byte 0xb0 + # bits value name desc + # 8-31 addr Data Address dest of the read + + .byte 0x20 + # bits value name desc + # 32 0 Chain-Data (CD) don't chain + # 33 0 Chain-Command (CC) don't chain + # 34 1 Sup.-Len.-Inditcation (SLI) suppress + # 35 0 Skip (SKP) issue read + # 36 0 Prog.-Contr.-Inter. (PCI) don't interrupt + # 37 0 Indir.-Data-Addr. (IDA) real addr + # 38 0 Suspend (S) don't suspend + # 39 0 Modified I.D.A. (MIDA) real addr + + .byte 0x00 + # bits value name desc + # 40-47 0 + + .byte CCW2H + .byte CCW2L + # bits value name desc + # 48-63 len number of bytes to read + +# +# For whatever reason, it would seem that we need to pad until byte 0x50 = 80 +# + .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 24-31 + .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 32-39 + .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 40-47 + .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 48-55 + .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 56-63 + .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 64-71 + .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 # bytes 72-79 + diff --git a/ipl/linker.script b/ipl/linker.script new file mode 100644 index 0000000..d91ff61 --- /dev/null +++ b/ipl/linker.script @@ -0,0 +1,9 @@ +SECTIONS +{ + ENTRY(load_nucleus) + . = 0x800020; + .text : { *(.text) } + .data : { *(.data) } + .rodata : { *(.rodata) } + .bss : { *(.bss) } +} diff --git a/ipl/loader.c b/ipl/loader.c new file mode 100644 index 0000000..fe34efa --- /dev/null +++ b/ipl/loader.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2007 Josef 'Jeff' Sipek + */ + +#ifndef BYTES_TO_READ +#error missing BYTES_TO_READ +#endif + +#if BYTES_TO_READ > 0x300000 +#error The nucleus size is limited to 3MB +#endif + +#ifndef BLOCK_SIZE +#error missing BLOCK_SIZE +#endif + +#define TEMP_BASE ((unsigned char*) 0x400000) /* 4MB */ + +typedef unsigned long u64; +typedef signed long s64; + +typedef unsigned int u32; +typedef signed int s32; + +typedef unsigned short u16; +typedef signed short s16; + +typedef unsigned char u8; +typedef signed char s8; + +#include + +static unsigned char seek_ccw[8] __attribute__ ((aligned (8))) = { + /* + * CCW1; seek to the right place + */ + + 0x3F, + /* bits value name desc */ + /* 0-7 2 Cmd Code ?, modifiers */ + + 0x00,0x00,0x00, + /* bits value name desc */ + /* 8-31 addr Data Address dest of the read */ + + 0x20, + /* bits value name desc */ + /* 32 0 Chain-Data (CD) don't chain */ + /* 33 1 Chain-Command (CC) don't chain */ + /* 34 1 Sup.-Len.-Inditcation (SLI) suppress */ + /* 35 0 Skip (SKP) issue read */ + /* 36 0 Prog.-Contr.-Inter. (PCI) don't interrupt */ + /* 37 0 Indir.-Data-Addr. (IDA) real addr */ + /* 38 0 Suspend (S) don't suspend */ + /* 39 0 Modified I.D.A. (MIDA) real addr */ + + 0x00, + /* bits value name desc */ + /* 40-47 0 */ + + 0x00,0x01, + /* bits value name desc */ + /* 48-63 len number of bytes to read */ +}; + +static unsigned char read_ccw[8] __attribute__ ((aligned (8))) = { + /* + * CCW2; read the entire nucleus ELF + */ + + 0x02, + /* bits value name desc */ + /* 0-7 2 Cmd Code read, no modifiers*/ + + 0xff, 0xff, 0xff, + /* bits value name desc */ + /* 8-31 addr Data Address dest of the read */ + + 0x20, + /* bits value name desc */ + /* 32 0 Chain-Data (CD) don't chain */ + /* 33 0 Chain-Command (CC) don't chain */ + /* 34 1 Sup.-Len.-Inditcation (SLI) suppress */ + /* 35 0 Skip (SKP) issue read */ + /* 36 0 Prog.-Contr.-Inter. (PCI) don't interrupt */ + /* 37 0 Indir.-Data-Addr. (IDA) real addr */ + /* 38 0 Suspend (S) don't suspend */ + /* 39 0 Modified I.D.A. (MIDA) real addr */ + + 0x00, + /* bits value name desc */ + /* 40-47 0 */ + + 0xff, 0xff, + /* bits value name desc */ + /* 48-63 len number of bytes to read */ +}; + +unsigned char ORB[32] __attribute__ ((aligned (16))) = { + /* Word 0 */ + 0x12,0x34,0x56,0x78, + /* bits value name desc */ + /* 0-31 magic Interrupt Parameter */ + + /* Word 1 */ + 0x00, + /* bits value name desc */ + /* 0-3 0 Subchannel Key */ + /* 4 0 Suspend Control */ + /* 5 0 Streaming-Mode Control */ + /* 6 0 Modification Control */ + /* 7 0 Synchronization Control */ + + 0x00, + /* bits value name desc */ + /* 8 0 Format Control format-0 CCWs */ + /* 9 0 Prefetch Control */ + /* 10 0 Initial-Status-Interruption Control */ + /* 11 0 Address-Limit-Checking Control */ + /* 12 0 Suppress-Suspended-Interruption Control */ + /* 13 0 */ + /* 14 0 Format-2-IDAW Control */ + /* 15 0 2K-IDAW Control */ + + 0xff, + /* bits value name desc */ + /* 16-23 0xff Logical-Path Mask All paths */ + + 0x00, + /* bits value name desc */ + /* 24 0 Incorrect-Length-Suppression Mode */ + /* 25 0 Modified-CCW-Indirect-Data-Addressing Control*/ + /* 26-30 0 */ + /* 31 0 ORB-Extension Control */ + + /* Word 2 */ + 0xff,0xff,0xff,0xff, + /* bits value name desc */ + /* 0-31 addr Channel-Program Address */ + + /* Word 3 */ + 0x00, + /* bits value name desc */ + /* 0-7 0 Channel-Subsystem Priority */ + + 0x00, + /* bits value name desc */ + /* 8-15 0 */ + + 0x00, + /* bits value name desc */ + /* 15-23 0 Control-Unit Priority */ + + 0x00, + /* bits value name desc */ + /* 24-31 0 */ + + /* Word 4 */ + 0x00,0x00,0x00,0x00, + /* bits value name desc */ + /* 0-31 0 */ + + /* Word 5 */ + 0x00,0x00,0x00,0x00, + /* bits value name desc */ + /* 0-31 0 */ + + /* Word 6 */ + 0x00,0x00,0x00,0x00, + /* bits value name desc */ + /* 0-31 0 */ + + /* Word 7 */ + 0x00,0x00,0x00,0x00, + /* bits value name desc */ + /* 0-31 0 */ +}; + +static inline void *memcpy(void *dst, void *src, int len) +{ + unsigned char *d = dst; + unsigned char *s = src; + + while(len--) + *d++ = *s++; + + return dst; +} + +/* + * halt the cpu + * + * NOTE: we don't care about not clobbering registers as when this + * code executes, the CPU will be stopped. + */ +static inline void die() +{ + asm volatile( + "SR %r1, %r1 # not used, but should be zero\n" + "SR %r3, %r3 # CPU Address\n" + "SIGP %r1, %r3, 0x05 # Signal, order 0x05\n" + ); + + /* + * Just in case SIGP fails + */ + for(;;); +} + +/* + * It is easier to write this thing in assembly... + */ +extern void __do_io(); + +/* + * read the entire nucleus into into TEMP_BASE + */ +static inline void readnucleus() +{ + register unsigned long base; + + /* + * First, seek past the tape mark + */ + + /* set the CCW address in the ORB */ + *((u32 *) &ORB[8]) = (u32) seek_ccw; + + __do_io(); + + /* + * Second, read in BLOCK_SIZE chunks of nucleus + */ + + /* set the CCW address in the ORB */ + *((u32 *) &ORB[8]) = (u32) read_ccw; + + read_ccw[6] = ((unsigned char) (BLOCK_SIZE >> 8) & 0xff); + read_ccw[7] = ((unsigned char) (BLOCK_SIZE & 0xff)); + + base = (unsigned long) TEMP_BASE; + for( ; + (base - (unsigned long)TEMP_BASE) < BYTES_TO_READ; + base += BLOCK_SIZE) { + read_ccw[1] = ((unsigned char) (base >> 16)); + read_ccw[2] = ((unsigned char) (base >> 8) & 0xff); + read_ccw[3] = ((unsigned char) (base & 0xff)); + __do_io(); + } +} + +void load_nucleus(void) +{ + /* + * These are all stored in registers + */ + register int i; + register Elf64_Ehdr *nucleus_elf; + register Elf64_Shdr *section; + register void (*start_sym)(void); + + /* + * Read entire ELF to temporary location + */ + readnucleus(); + + nucleus_elf = (Elf64_Ehdr*) TEMP_BASE; + + /* + * Check that this looks like a valid ELF + */ + if (nucleus_elf->e_ident[0] != '\x7f' || + nucleus_elf->e_ident[1] != 'E' || + nucleus_elf->e_ident[2] != 'L' || + nucleus_elf->e_ident[3] != 'F' || + nucleus_elf->e_ident[EI_CLASS] != ELFCLASS64 || + nucleus_elf->e_ident[EI_DATA] != ELFDATA2MSB || + nucleus_elf->e_ident[EI_VERSION] != EV_CURRENT || + nucleus_elf->e_type != ET_EXEC || + nucleus_elf->e_machine != 0x16 || // FIXME: find the name for the #define + nucleus_elf->e_version != EV_CURRENT) + die(); + + /* + * Iterate through each section, and copy it to the final + * destination as necessary + */ + for (i=0; ie_shnum; i++) { + section = (Elf64_Shdr*) (TEMP_BASE + + nucleus_elf->e_shoff + + nucleus_elf->e_shentsize * i); + + switch (section->sh_type) { + case SHT_PROGBITS: + if (!section->sh_addr) + break; + + /* + * just copy the data from TEMP_BASE to + * where it wants to be + */ + memcpy((void*) section->sh_addr, + TEMP_BASE + section->sh_offset, + section->sh_size); + break; + case SHT_NOBITS: + /* + * No action needed as there's no data to + * copy, and we assume that the ELF sections + * don't overlap + */ + break; + case SHT_SYMTAB: + case SHT_STRTAB: + /* TODO: relocate */ + break; + default: + /* Ignoring */ + break; + } + } + + /* + * Now, jump to the nucleus entry point + */ + start_sym = (void*) nucleus_elf->e_entry; + start_sym(); +} diff --git a/ipl/loader_asm.S b/ipl/loader_asm.S new file mode 100644 index 0000000..9655c18 --- /dev/null +++ b/ipl/loader_asm.S @@ -0,0 +1,208 @@ +# +# Copyright (c) 2007 Josef 'Jeff' Sipek +# + +.text + .align 4 +.globl __do_io + .type __do_io, @function +__do_io: + # + # r4 = 0x80000000 + # + SR %r4, %r4 + LHI %r4, 0x8 + SLL %r4, 20 + # + # r14 = r14 & 0x7fffffff don't ask, it's strangely retarded + # + L %r1,ADDRMASK(%r4) + NR %r14, %r1 # mask out the bit + + # set up the interrupt handler + MVC 0x1f0(16),IOPSW(%r4) # SET NEW IO PSW + LA %r1,IOHANDLER(%r4) # GET HANDLER ADDRESS + STG %r1,0x1f0+8 # SAVE IN NEW PSW + + L %r1, 0xb8 # load subsystem ID + + SSCH ORB(%r4) # issue IO + + # Load Control Register 6 with I/O interrupt subclass mask + STCTG 6,6,TMPVAR(%r4) # GET CR6 + OI TMPVAR+4(%r4),0xFF # enable all + LCTLG 6,6,TMPVAR(%r4) # RELOAD MODIFIED CR6 + +/* +7) Enable the PSW for I/O interrupts and go into wait state (you need bits 6, 12 & 14 set to 1 in the PSW : X'020A000000000000' is a good example) +*/ + LA %r3, RETURN(%r4) # interrupt return address + #STG %r1, WAITPSW+8(%r4) + + LPSWE WAITPSW(%r4) + +RETURN: + SR %r2, %r2 # return 0 + BR %r14 # Done, let's go back to C! + +# +# The IO interrupt handler +# +.globl IOHANDLER +IOHANDLER: + # is this for us? + L %r1, MAGICVAL(%r4) + C %r1, 0xbc + BNE IONOTDONE(%r4) + + # it is! + + L %r1, 0xb8 # load subsystem ID + + TSCH IRB(%r4) + + # check the SCSW.. If CE Only : LPSW Old I/O PSW + L %r1, IRB+5(%r4) + NILL %r1, 0x04 + BC 8, IONOTDONE(%r4) # not device end => LPSWE + +/* +FIXME: we should do more checking! + +11) If Unit check or Channel Status|=0 : An I/O error occurred and act accordingly +12) If unit exception : End of media (for tape & cards) and act accordingly +13) If device end : I/O Completed.. Perform post I/O stuff (like advancing your pointers) and back to step 3 +*/ + + # return to the "caller" + BR %r3 + +IONOTDONE: + LPSWE 0x170 + +# +# Useful data +# +.data + .align 8 +.globl IOPSW +IOPSW: + .byte 0x00 + # bits value name desc + # 0 0 + # 1 0 PER Mask (R) disabled + # 2-4 0 + # 5 0 DAT Mode (T) disabled + # 6 0 I/O Mask (IO) enabled + # 7 0 External Mask (EX) disabled + + .byte 0x04 + # bits value name desc + # 8-11 0 Key + # 12 0 + # 13 1 Machine-Check Mask (M) enabled + # 14 0 Wait State (W) executing + # 15 0 Problem State (P) supervisor state + + .byte 0x00 + # bits value name desc + # 16-17 0 Address-Space Control (AS) disabled + # 18-19 0 Condition Code (CC) + # 20-23 0 Program Mask exceptions disabled + + .byte 0x01 + # bits value name desc + # 24-30 0 + # 31 1 Extended Addressing (EA) EA + BA = 64 mode + + .byte 0x80 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + # bits value name desc + # 32 1 Basic Addressing (BA) BA = 31, !BA = 24 + # 33-63 0 + # 64-127 addr Instruction Address Address to exec + +.globl WAITPSW +WAITPSW: + .byte 0x02 + # bits value name desc + # 0 0 + # 1 0 PER Mask (R) disabled + # 2-4 0 + # 5 0 DAT Mode (T) disabled + # 6 1 I/O Mask (IO) enabled + # 7 0 External Mask (EX) disabled + + .byte 0x06 + # bits value name desc + # 8-11 0 Key + # 12 0 + # 13 1 Machine-Check Mask (M) enabled + # 14 1 Wait State (W) executing + # 15 0 Problem State (P) supervisor state + + .byte 0x00 + # bits value name desc + # 16-17 0 Address-Space Control (AS) disabled + # 18-19 0 Condition Code (CC) + # 20-23 0 Program Mask exceptions disabled + + .byte 0x01 + # bits value name desc + # 24-30 0 + # 31 1 Extended Addressing (EA) EA + BA = 64 mode + + .byte 0x80 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + # bits value name desc + # 32 1 Basic Addressing (BA) BA = 31, !BA = 24 + # 33-63 0 + # 64-127 addr Instruction Address Address to exec + +.globl TMPVAR +TMPVAR: + .8byte 0x0 + +.globl ADDRMASK +ADDRMASK: + .4byte 0x7fffffff + +.globl MAGICVAL +MAGICVAL: + .4byte 0x12345678 + +.globl IRB +IRB: + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + .8byte 0x00 + diff --git a/ipl/setmode.S b/ipl/setmode.S new file mode 100644 index 0000000..ce08bf0 --- /dev/null +++ b/ipl/setmode.S @@ -0,0 +1,47 @@ +# +# Copyright (c) 2007 Josef 'Jeff' Sipek +# + +# +# At this point, the machine is running in ESA390 mode. Let's load a new +# PSW, making it switch to 64-bit mode +# + + # switch to 64-bit mode + # + # Signal Processor + # Order 0x12: Set Architecture + # R1 bits 56-63 = 0x01 (switch all CPUs to z/Arch) + SR %r1, %r1 + LHI %r1, 0x1 # switch all to z/Arch + SR %r3, %r3 # CPU Address (CPU0000) + SIGP %r1, %r3, 0x12 # Signal, order 0x12 + # On error: + # Bit 55 = 1, cc1 (inval param) + # Bit 54 = 1, cc1 (incorrect state) + + # FIXME: check for errors? + +# +# At this point, we should be in 64-bit mode +# + + # + # It is unfortunate that the below code is required. + # + # Let's set the stack pointer to make gcc happy + # + + # r15 = 0x800000 + # = (8 << 20) + # + SR %r15, %r15 + LHI %r15, 0x8 + SLL %r15, 20 + AHI %r15, -160 + +# +# Padding to make the entire file 0x20 bytes +# + BCR 0, %r7 + BCR 0, %r7 diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..b19c07a --- /dev/null +++ b/lib/Makefile @@ -0,0 +1 @@ +objs-lib := string.o vsprintf.o diff --git a/lib/string.c b/lib/string.c new file mode 100644 index 0000000..df5f16d --- /dev/null +++ b/lib/string.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2007 Josef 'Jeff' Sipek + */ + +void *memset(void *s, int c, size_t n) +{ + unsigned char *ptr = s; + + while(n--) + *ptr++ = c; + + return s; +} + +void *memcpy(void *dst, void *src, int len) +{ + unsigned char *d = dst; + unsigned char *s = src; + + while(len--) + *d++ = *s++; + + return dst; +} + +int strnlen(const char *s, size_t maxlen) +{ + int len; + + for(len=0; *s && len <= maxlen; s++, len++) + ; + + return len; +} diff --git a/lib/vsprintf.c b/lib/vsprintf.c new file mode 100644 index 0000000..82c98b1 --- /dev/null +++ b/lib/vsprintf.c @@ -0,0 +1,391 @@ +/* + * A number of things found in this file were borrowed from the Linux Kernel + */ + +#include + +/* + * The following constants should not be available to any users outside this + * C file, as they are rather meaningless there. + */ + +/* borrowed from Linux */ +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define isdigit(c) (((c) >= '0') && ((c) <= '9')) + +/* borrowed from Linux */ +# define do_div(n,base) ({ \ + u32 __base = (base); \ + u32 __rem; \ + __rem = ((u64)(n)) % __base; \ + (n) = ((u64)(n)) / __base; \ + __rem; \ + }) + +/* borrowed from Linux */ +static int skip_atoi(const char **s) +{ + int i=0; + + while (isdigit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +/* borrowed from Linux */ +static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type) +{ + char c,sign,tmp[66]; + const char *digits; + static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + digits = (type & LARGE) ? large_digits : small_digits; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return NULL; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if ((signed long long) num < 0) { + sign = '-'; + num = - (signed long long) num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) { + while(size-->0) { + if (buf < end) + *buf = ' '; + ++buf; + } + } + if (sign) { + if (buf < end) + *buf = sign; + ++buf; + } + if (type & SPECIAL) { + if (base==8) { + if (buf < end) + *buf = '0'; + ++buf; + } else if (base==16) { + if (buf < end) + *buf = '0'; + ++buf; + if (buf < end) + *buf = digits[33]; + ++buf; + } + } + if (!(type & LEFT)) { + while (size-- > 0) { + if (buf < end) + *buf = c; + ++buf; + } + } + while (i < precision--) { + if (buf < end) + *buf = '0'; + ++buf; + } + while (i-- > 0) { + if (buf < end) + *buf = tmp[i]; + ++buf; + } + while (size-- > 0) { + if (buf < end) + *buf = ' '; + ++buf; + } + return buf; +} + +/** + * vsnprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @size: The size of the buffer, including the trailing null space + * @fmt: The format string to use + * @args: Arguments for the format string + * + * The return value is the number of characters which would + * be generated for the given input, excluding the trailing + * '\0', as per ISO C99. If you want to have the exact + * number of characters written into @buf as return value + * (not including the trailing '\0'), use vscnprintf(). If the + * return is greater than or equal to @size, the resulting + * string is truncated. + * + * Call this function if you are already dealing with a va_list. + * You probably want snprintf() instead. + * + * NOTE: This function was borrowed from Linux's lib/vsprintf.c + */ +int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) +{ + int len; + unsigned long long num; + int i, base; + char *str, *end, c; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + /* 'z' support added 23/7/1999 S.H. */ + /* 'z' changed to 'Z' --davidm 1/25/99 */ + /* 't' added for ptrdiff_t */ + + /* Reject out-of-range values early. Large positive sizes are + used for unknown buffer sizes. */ + if (unlikely((int) size < 0)) + return 0; + + str = buf; + end = buf + size; + + /* Make sure end is always >= buf */ + if (end < buf) { + end = ((void *)-1); + size = end - buf; + } + + for (; *fmt ; ++fmt) { + if (*fmt != '%') { + if (str < end) + *str = *fmt; + ++str; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || + *fmt =='Z' || *fmt == 'z' || *fmt == 't') { + qualifier = *fmt; + ++fmt; + if (qualifier == 'l' && *fmt == 'l') { + qualifier = 'L'; + ++fmt; + } + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) { + while (--field_width > 0) { + if (str < end) + *str = ' '; + ++str; + } + } + c = (unsigned char) va_arg(args, int); + if (str < end) + *str = c; + ++str; + while (--field_width > 0) { + if (str < end) + *str = ' '; + ++str; + } + continue; + + case 's': + s = va_arg(args, char *); + if ((unsigned long)s < PAGE_SIZE) + s = ""; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) { + while (len < field_width--) { + if (str < end) + *str = ' '; + ++str; + } + } + for (i = 0; i < len; ++i) { + if (str < end) + *str = *s; + ++str; ++s; + } + while (len < field_width--) { + if (str < end) + *str = ' '; + ++str; + } + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, end, + (unsigned long) va_arg(args, void *), + 16, field_width, precision, flags); + continue; + + + case 'n': + /* FIXME: + * What does C99 say about the overflow case here? */ + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else if (qualifier == 'Z' || qualifier == 'z') { + size_t * ip = va_arg(args, size_t *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + if (str < end) + *str = '%'; + ++str; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + if (str < end) + *str = '%'; + ++str; + if (*fmt) { + if (str < end) + *str = *fmt; + ++str; + } else { + --fmt; + } + continue; + } + if (qualifier == 'L') + num = va_arg(args, long long); + else if (qualifier == 'l') { + num = va_arg(args, unsigned long); + if (flags & SIGN) + num = (signed long) num; + } else if (qualifier == 'Z' || qualifier == 'z') { + num = va_arg(args, size_t); + } else if (qualifier == 't') { + num = va_arg(args, ptrdiff_t); + } else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (signed short) num; + } else { + num = va_arg(args, unsigned int); + if (flags & SIGN) + num = (signed int) num; + } + str = number(str, end, num, base, + field_width, precision, flags); + } + if (size > 0) { + if (str < end) + *str = '\0'; + else + end[-1] = '\0'; + } + /* the trailing null byte doesn't count towards the total */ + return str-buf; +} + diff --git a/linker.script b/linker.script new file mode 100644 index 0000000..a465580 --- /dev/null +++ b/linker.script @@ -0,0 +1,8 @@ +SECTIONS +{ + ENTRY(start) + . = 0x100000; + .text : { *(.text) } + .data : { *(.data) } + .bss : { *(.bss) } +} diff --git a/mm/Makefile b/mm/Makefile new file mode 100644 index 0000000..b594388 --- /dev/null +++ b/mm/Makefile @@ -0,0 +1 @@ +objs-mm := buddy.o page.o slab.o diff --git a/mm/buddy.c b/mm/buddy.c new file mode 100644 index 0000000..5827ad0 --- /dev/null +++ b/mm/buddy.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2007 Josef 'Jeff' Sipek + */ + +#include +#include +#include +#include + +/* + * Lists of free page ranges + */ +static struct list_head orders[64-PAGE_SHIFT]; + +void init_buddy_alloc(u64 start) +{ + int pages = (memsize - start) >> PAGE_SHIFT; + int order; + u64 base = start; + struct page *p; + + for(order=0; order < (64-PAGE_SHIFT); order++) { + INIT_LIST_HEAD(&orders[order]); + + if (pages & (1 << order)) { + p = page_num_to_ptr(base >> PAGE_SHIFT); + + list_add(&p->buddy, &orders[order]); + + base += (PAGE_SIZE << order); + } + } +} + +static struct page *__alloc_pages(int order) +{ + struct list_head *entry; + + /* + * If there is a right-sized series of pages, good! + */ + if (!list_empty(&orders[order])) { + entry = orders[order].next; + list_del(entry); + + return list_entry(entry, struct page, buddy); + } + + return NULL; +} + +/* + * Split a given (actual) order allocation into an allocation of wanted + * order, and return the rest of pages to the unused lists + * + * E.g., + * + * pages (base): + * + * +---+---+---+---+---+---+---+---+ + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + * +---+---+---+---+---+---+---+---+ + * + * actual = 3 + * wanted = 1 + * + * return order 2 range back to free pool: + * + * +---+---+---+---+ + * | 4 | 5 | 6 | 7 | + * +---+---+---+---+ + * + * return order 1 range back to free pool: + * + * +---+---+ + * | 2 | 3 | + * +---+---+ + * + * The End. Now, pages 2-7 are back in the free pool, and pages 0&1 are an + * order 1 allocation. + * + */ +static void __chip_pages(struct page *base, int actual, int wanted) +{ + struct page *p; + + for(; actual > wanted; actual--) { + p = &base[1 << (actual-1)]; + list_add(&p->buddy, &orders[actual-1]); + } +} + +struct page *alloc_pages(int order) +{ + struct page *page; + int gord; + + /* easy way */ + page = __alloc_pages(order); + if (page) + return page; + + /* + * There is no page-range of the given order, let's try to find the + * smallest one larger and split it + */ + + for(gord=order+1; gord < (64-PAGE_SHIFT); gord++) { + page = __alloc_pages(gord); + if (!page) + continue; + + __chip_pages(page, gord, order); + + return page; + } + + /* alright, totally out of memory */ + return NULL; +} + +void free_pages(void *ptr, int order) +{ + struct page *base = addr_to_page(ptr); + + list_add(&base->buddy, &orders[order]); + + /* + * TODO: a more complex thing we could try is to coallesce adjecent + * page ranges into one higher order one (defrag) + */ +} diff --git a/mm/page.c b/mm/page.c new file mode 100644 index 0000000..470e3a9 --- /dev/null +++ b/mm/page.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2007 Josef 'Jeff' Sipek + */ + +#include +#include +#include + +/* + * Main storage size + */ +u64 memsize; + +/* + * Initialize fields in a struct page + */ +static void __init_page(struct page *page) +{ + INIT_LIST_HEAD(&page->buddy); +} + +/* + * Initialize struct page for each available page + */ +void init_pages() +{ + u64 pnum; + + for(pnum=0; pnum < (memsize>>PAGE_SHIFT); pnum++) + __init_page(page_num_to_ptr(pnum)); +} + diff --git a/mm/slab.c b/mm/slab.c new file mode 100644 index 0000000..490af56 --- /dev/null +++ b/mm/slab.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2007 Josef 'Jeff' Sipek + */ + +#include +#include +#include + +static struct slab *generic[5]; + +/* + * Create slab caches for 16, 32, 64, 128, and 256 byte allocations + */ +int init_slab() +{ + generic[0] = create_slab(16); + if (!generic[0]) + goto out_err; + + generic[1] = create_slab(32); + if (!generic[1]) + goto out_err; + + generic[2] = create_slab(64); + if (!generic[2]) + goto out_err; + + generic[3] = create_slab(128); + if (!generic[3]) + goto out_err; + + generic[4] = create_slab(256); + if (!generic[4]) + goto out_err; + + return 0; + +out_err: + free_slab(generic[0]); + free_slab(generic[1]); + free_slab(generic[2]); + free_slab(generic[3]); + free_slab(generic[4]); + + return -ENOMEM; +} + +struct slab *create_slab(u16 objsize) +{ + struct page *page; + struct slab *slab; + + page = alloc_pages(0); + if (!page) + return NULL; + + slab = page_to_addr(page); + memset(slab, 0, PAGE_SIZE); + + slab->next = NULL; + slab->objsize = objsize; + slab->count = 8 * (PAGE_SIZE - sizeof(struct slab)) / (8 * objsize + 1); + slab->used = 0; + + return slab; +} + +void free_slab(struct slab *slab) +{ + struct slab *next; + + if (!slab) + return; + + for(next = slab->next; slab; slab = next) { + /* + * TODO: debugging support should check if slab->used != 0 + */ + free_pages(slab, 0); + } +} + +static inline void *__alloc_slab_obj_newpage(struct slab *slab) +{ + struct page *page; + + page = alloc_pages(0); + if (!page) + return ERR_PTR(-ENOMEM); + + slab->next = page_to_addr(page); + + return slab->next; +} + +void *alloc_slab_obj(struct slab *slab) +{ + int objidx; + u8 *bits; + u8 mask; + + if (!slab) + return NULL; + + /* + * Find the first slab page that has unused objects + */ + while((slab->used == slab->count) && slab->next) + slab = slab->next; + + if ((slab->used == slab->count) && !slab->next) { + slab = __alloc_slab_obj_newpage(slab); + if (PTR_ERR(slab)) + return NULL; + } + + /* found a page */ + for (objidx = 0; objidx < slab->count; objidx++) { + bits = ((u8 *) slab) + sizeof(struct slab) + (objidx/8); + + mask = 1 << (7 - (objidx % 8)); + + if (*bits & mask) + continue; + + slab->used++; + *bits |= mask; + + return ((u8*) slab) + slab->startoff + slab->objsize * objidx; + } + + /* SOMETHING STRANGE HAPPENED */ + return NULL; +} + +void free_slab_obj(void *ptr) +{ + struct slab *slab; + int objidx; + u8 *bits; + + /* get the slab object ptr */ + slab = (struct slab *) (((u64) ptr) & ~0xfff); + + /* calculate the object number */ + objidx = (((u64) ptr) - ((u64) slab) - slab->startoff) / slab->objsize; + + /* update the bitmap */ + bits = ((u8 *) slab) + sizeof(struct slab) + (objidx/8); + *bits &= ~(1 << (7 - (objidx % 8))); + + if (--slab->used) { + /* free the page? */ + } +} + +void *malloc(int size) +{ + if (size <= 16) + return alloc_slab_obj(generic[0]); + if (size <= 32) + return alloc_slab_obj(generic[1]); + if (size <= 64) + return alloc_slab_obj(generic[2]); + if (size <= 128) + return alloc_slab_obj(generic[3]); + if (size <= 256) + return alloc_slab_obj(generic[4]); + return NULL; +} + +void free(void *ptr) +{ + free_slab_obj(ptr); +} diff --git a/nucleus/Makefile b/nucleus/Makefile new file mode 100644 index 0000000..94f5645 --- /dev/null +++ b/nucleus/Makefile @@ -0,0 +1 @@ +objs-nucleus := init.o io.o printf.o diff --git a/nucleus/init.c b/nucleus/init.c new file mode 100644 index 0000000..23737fa --- /dev/null +++ b/nucleus/init.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2007 Josef 'Jeff' Sipek + */ + +#include +#include +#include +#include +#include + +static inline void die() +{ + /* + * halt the cpu + * + * NOTE: we don't care about not clobbering registers as when this + * code executes, the CPU will be stopped. + */ + asm volatile( + "SR %r1, %r1 # not used, but should be zero\n" + "SR %r3, %r3 # CPU Address\n" + "SIGP %r1, %r3, 0x05 # Signal, order 0x05\n" + ); + + /* + * If SIGP failed, loop forever + */ + for(;;); +} + +/* + * This is where everything starts + */ +void start() +{ + u64 first_free_page; + u64 struct_page_bytes; + + /* + * We should determine this dynamically + */ + memsize = MEMSIZE; + + /* + * Initialize struct page entries + */ + init_pages(); + + /* + * Calculate address of the first free page (we may have to round + * up) + */ + struct_page_bytes = (memsize >> PAGE_SHIFT) * sizeof(struct page); + + first_free_page = (u64) PAGE_INFO_BASE + struct_page_bytes; + if (struct_page_bytes & (PAGE_SIZE-1)) + first_free_page += PAGE_SIZE - (struct_page_bytes & (PAGE_SIZE-1)); + + /* + * Initialize the buddy allocator + */ + init_buddy_alloc(first_free_page); + + /* + * Initialize slab allocator default caches + */ + init_slab(); + + /* + * Initialize the io subsystem + */ + init_io(); + + /* + * To be or not to be + */ + die(); +} + diff --git a/nucleus/io.c b/nucleus/io.c new file mode 100644 index 0000000..40a3ea9 --- /dev/null +++ b/nucleus/io.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2007 Josef 'Jeff' Sipek + */ + +#include +#include +#include +#include + +static atomic_t ops_used; /* # of used slots in ops[] */ +static struct io_op_inflight_entry ops[MAX_IOS]; + /* in-flight I/O ops */ + +/* + * Helper function to make sure the io_op has everything set right + */ +static int __verify_io_op(struct io_op *ioop) +{ + // FIXME: check everything that makes sense to check + return 0; +} + +/* + * Submit an I/O request to a subchannel, and set up everything needed to + * handle the operation + */ +int submit_io(struct io_op *ioop, int flags) +{ + int i; + int err = -EBUSY; + + /* FIXME: is this condition right, or should it be negated? */ + if (atomic_add_unless(&ops_used, 1, MAX_IOS)) + goto out; + + err = __verify_io_op(ioop); + if (err) + goto out; + + ioop->err = 0; + ioop->done = 0; + + /* find an unused slot */ + for(i=0; iorb.param = i; + + /* + * Set the subsystem ID & issue SSCH on the ORB + */ + asm volatile( + " l %%r1,%0\n" + " ssch %1\n" + : /* output */ + : /* input */ + "d" (ioop->ssid), + "d" (&ioop->orb) + : /* clobbered */ + "cc", "r1" + ); + + err = 0; +out: + return err; +} + +/* + * Initialize the channel I/O subsystem + */ +void init_io() +{ + int i; + + for(i=0; iparam >= MAX_IOS) + return; + + cur_op = ops[IO_INT_CODE->param].op; + if (!cur_op) + return; + + if (cur_op->handler) + cur_op->handler(cur_op, &irb); + + /* + * We can do this, because the submit_io function resets ->err to + * zero, and therefore regardless of ->handler being defined, ->err + * will have a reasonable value + */ + if (cur_op->err == -EAGAIN) + return; /* leave handler registered */ + + /* flag io_op as done... */ + cur_op->done = 1; + + /* ...and remove it form the list */ + ops[IO_INT_CODE->param].op = NULL; + atomic_dec(&ops[IO_INT_CODE->param].used); + atomic_dec(&ops_used); +} diff --git a/nucleus/printf.c b/nucleus/printf.c new file mode 100644 index 0000000..5579b3f --- /dev/null +++ b/nucleus/printf.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2007 Josef 'Jeff' Sipek + */ + +int vprintf(const char *fmt, va_list args) +{ + static char buf[80]; + int ret; + + ret = vsnprintf(buf, 80, fmt, args); + + return ret; +} + +/* + * Logic borrowed from Linux's printk + */ +int printf(const char *fmt, ...) +{ + va_list args; + int r; + + va_start(args, fmt); + r = vprintf(fmt, args); + va_end(args); + + return r; +} diff --git a/scripts/gen_ipl_s.sh b/scripts/gen_ipl_s.sh new file mode 100755 index 0000000..4c7834d --- /dev/null +++ b/scripts/gen_ipl_s.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# +# Copyright (c) 2007 Josef 'Jeff' Sipek +# + +len=80 # this is going the be the size of ipl.rto +len=$(expr $len + `stat -c %s ipl/setmode.rto`) +len=$(expr $len + `stat -c %s ipl/loader.rto`) +dif=`expr $len % 80` + +if [ $dif -ne 0 ]; then + len=`expr $len - $dif` + len=`expr $len + 80` +fi + +if [ $len -gt `expr 65536` ]; then + echo "ERROR: loader code is too long" >&2 + exit 1 +fi + +ccw2=$len + +ccw2h=`expr $ccw2 / 256` +ccw2l=`expr $ccw2 % 256` + +sed -e "s/CCW2H/$ccw2h/g" \ + -e "s/CCW2L/$ccw2l/g" \ + "$1" > "$2" -- 2.11.4.GIT