diff options
178 files changed, 17952 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2aa725e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +*.tgz +*.iso +*.img diff --git a/sos-code-article1/INSTALL b/sos-code-article1/INSTALL new file mode 100644 index 0000000..7c7d619 --- /dev/null +++ b/sos-code-article1/INSTALL @@ -0,0 +1,118 @@ + + SOS: A Simple Operating System + + Compilation/Installation/Test instructions + + +Compilation +=========== + +IMPORTANT +--------- + +Don't forget to run 'make clean' before 'make' after you have modified +any source or header file(s). + + +On a x86 host where grub is correctly installed +----------------------------------------------- + +Simply run 'make' + + +On a non-x86 host (without grub of course !) +-------------------------------------------- + +See extra/README + + +On an x86 host without Grub, or with a buggy Grub +------------------------------------------------- + +See extra/README + +How do I know I have a buggy grub installation ? Answer: in the qemu +PC emulator, Grub hangs while loading the kernel + + +Installation +============ + +Nothing special to do besides compiling + + +Test the SOS Kernel +=================== + +On a x86 real machine with Grub installed +----------------------------------------- + + 1st method + => Boot the sos.elf file (append 'kernel=<path_to>sos.elf' in the + menu.lst or type it on Grub's command line) from a hard disk, a + floppy, or from the network + + 2nd method + => Copy the file 'fd.img' to a floppy and boot from it + + +On a x86 real machine without Grub installed +-------------------------------------------- + + 1st method + => see extra/README to compile with the grub floppy image we provide, + copy the file 'fd.img' to a floppy, and boot from it + + 2nd method + => see extra/README to compile with the boot sector we provide (up to + article 2 only), copy the file 'extra/sos_bsect.img' to a floppy, + and boot from it + + +Inside a PC emulator (x86 and non-x86 hosts) +-------------------------------------------- + +Tested on both the bochs emulator (x86/linux, sparc/solaris and +ppc/linux hosts, 'apt-get install bochs-x vgabios' on debian +testing/unstable), and the qemu system emulator (with libsdl +installed: 'apt-get install libsdl1.2-dev' on debian +testing/unstable). + + 1/ Grub is installed on the host (x86 hosts only) + - - - - - - - - - - - - - - - - - - - - - - - - - + + bochs: boot from the file 'fd.img'. Example of a ~/.bochsrc: + floppya: 1_44=/home/d2/sos/fd.img, status=inserted + romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000 + vgaromimage: /usr/share/vgabios/vgabios.bin + megs:63 # 63 Mo de RAM + + qemu: run 'qemu -fda fd.img' + If grub hangs while loading the kernel, please go to method 2/ + + 2/ Grub is not installed (all hosts) + - - - - - - - - - - - - - - - - - - + + See extra/README to generate a floppy image with the Grub floppy + image we provide, and: + + bochs: boot from the file 'fd.img' + + qemu: run 'qemu -fda fd.img' + + 3/ Bonus: boot with the bootsector we provide (all hosts, up to art. 2 ONLY !) + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + See extra/README to generate a floppy image with the boot sector we + provide, and: + + bochs: boot from the file 'extra/sos_bsect.img' + + qemu: run 'qemu -fda extra/sos_qemu.img' + + NOTE: After article 2, this way of booting is not supported: please + use the method 2/ above. + + +-- +David Decotigny diff --git a/sos-code-article1/LICENSE b/sos-code-article1/LICENSE new file mode 100644 index 0000000..60549be --- /dev/null +++ b/sos-code-article1/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) 19yy 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. + + <signature of Ty Coon>, 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/sos-code-article1/Makefile b/sos-code-article1/Makefile new file mode 100644 index 0000000..a0c82b2 --- /dev/null +++ b/sos-code-article1/Makefile @@ -0,0 +1,52 @@ +CC=i586-elf-gcc +LD=i586-elf-ld +CFLAGS = -Wall -nostdlib -nostdinc -ffreestanding -DKERNEL_SOS +LDFLAGS = --warn-common +OBJECTS = bootstrap/multiboot.o \ + drivers/x86_videomem.o drivers/bochs.o \ + sos/klibc.o sos/main.o + +KERNEL_OBJ = sos.elf +MULTIBOOT_IMAGE = cdrom.iso +PWD := $(shell pwd) + +# Main target +all: $(MULTIBOOT_IMAGE) + +$(MULTIBOOT_IMAGE): $(KERNEL_OBJ) + # ./support/build_image.sh $@ $< + if [ ! -e cdrom/boot/grub/stage2_eltorito ]; then \ + echo "Please copy grub's stage2_eltorito to cdrom/boot/grub."; \ + exit -1; \ + fi + cp $(KERNEL_OBJ) cdrom + echo timeout 0 > cdrom/boot/grub/menu.lst + echo title Simple OS >> cdrom/boot/grub/menu.lst + echo kernel /$(KERNEL_OBJ) >> cdrom/boot/grub/menu.lst + genisoimage -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 \ + -boot-info-table -input-charset ascii -A SOS -o $(MULTIBOOT_IMAGE) cdrom + +$(KERNEL_OBJ): $(OBJECTS) + $(LD) $(LDFLAGS) -T ./support/sos.lds -o $@ $^ + -nm -C $@ | cut -d ' ' -f 1,3 > sos.map + +-include .mkvars + +# Create objects from C source code +%.o: %.c + $(CC) -I$(PWD) -c $< $(CFLAGS) -o $@ + +# Create objects from assembler (.S) source code +%.o: %.S + $(CC) -I$(PWD) -c $< $(CFLAGS) -DASM_SOURCE=1 -o $@ + +# Clean directory +clean: + $(RM) *.iso *.img *.o mtoolsrc *~ menu.txt *.img *.elf *.bin *.map + $(RM) *.log *.out bochs* + $(RM) bootstrap/*.o bootstrap/*~ + $(RM) drivers/*.o drivers/*~ + $(RM) hwcore/*.o hwcore/*~ + $(RM) sos/*.o sos/*~ + $(RM) support/*~ + $(RM) extra/*~ diff --git a/sos-code-article1/README b/sos-code-article1/README new file mode 100644 index 0000000..efbbc89 --- /dev/null +++ b/sos-code-article1/README @@ -0,0 +1,90 @@ + + SOS: A Simple Operating System + + +This is SOS, a Simple Operating System for i386-family +processors. This is as simple as possible to show a way to program a +basic Operating System on real common hardware (PC). The code should +be easily readable and understandable thanks to frequent comments, and +references to external documentation. We chose to implement the basic +features of an OS, thus making design decisions targetting towards +simplicity of understanding, covering most of the OS classical +concepts, but not aiming at proposing yet another full-fledged +competitive OS (Linux is quite good at it). However, for those who +would like to propose some enhancements, we are open to any code +suggestions (patches only, please). And yes, there might be bugs in +the code, so please send us any bug report, and/or patches ! + +The OS comes as a set of articles (in french) to be published in the +journal "Linux Magazine France". Each month, the part of the code +related to the current article's theme is released (see VERSION file), +and the resulting OS can be successfully compiled and run, by booting +it from a floppy on a real machine (tested AMD k7, Cyrix and Intel P4 +pentiums), or through an x86 emulator (bochs or qemu). The resulting +OS is available as a multiboot compliant ELF kernel (sos.elf) and as a +floppy image (fd.img). It provides a very very very basic demo whose +aim is to understand how everything works, not to animate sprites on +the screen with 5:1 dolby sound. + +The initial technical features and lack-of-features of the OS are: + - monolithic kernel, fully interruptible, non-preemptible (big kernel + lock), target machines = i386 PC or better + - compiles on any host where the gcc/binutils toolchain (target + i586-gnu) is available. Can be tested on real i486/pentium + hardware, or on any host that can run an i486/pentium PC emulator + (bochs or qemu) + - kernel loaded by grub, or by a sample bootsector (up to article 2 + ONLY) + - clear separation of physical memory and virtual memory concepts, + even inside the kernel: no identity-mapping of the physical memory + inside the kernel (allows to move virtual mappings of kernel pages + at run-time, eg to free ISA DMA pages, and to avercome the 4G RAM + barrier) + - slab-type kernel memory allocation + - no swap, no reverse mapping + - VERY simple drivers: keyboard, x86 video memory, IDE disks + - logical devices: partitions, FAT filesystem, "hard-coded" + mountpoints only (~ MSDOS) + - no network stack + - user-level features: ELF loader (no shared libraries), processes, + user threads (kernel-level scheduling only), mmap API, basic VFS + +To understand where to look at for what, here is a brief description: + - Makefile: the (ONLY) makefile of the OS. Targets are basically + 'all' and 'clean' + - bootstrap/ directory: code to load the kernel. Both the stuff + needed for a multiboot-compliant loader (eg grub) AND a bootsector + are provided. The bootsector may only be used up to article 2. + - sos/ directory: the entry routine for the kernel (main.c), various + systemwide header files, a set of common useful C routines + ("nano-klibc"), and kernel subsystems (kernel memory management, + etc...) + - hwcore/ directory: Low-level CPU- and kernel-related routines + (interrupt/exception management, translation tables and segment + registers, ...) + - drivers/ directory: basic kernel drivers for various (non CPU) + devices (keyboard, x86 video memory, bochs 0xe9 port, ...). Used + mainly for debugging + - support/ directory: scripts and configuration files to build the + floppy images + - extra/ directory: a set of configuration files to be customized for + non-x86 host installations (yes, we primarily develop SOS on a ppc, for + the x86 target of course), or for grub-less installations. See + README file in this directory. + +The code is licensed under the terms of the GNU GPL version 2 (see +LICENSE file). + +Enjoy ! + + David Decotigny, Thomas Petazzoni, the Kos team + http://sos.enix.org/ + http://david.decotigny.free.fr/ + http://kos.enix.org/~thomas/ + http://kos.enix.org/ + + +-- +David Decotigny + +PS: Made with a Mac. diff --git a/sos-code-article1/VERSION b/sos-code-article1/VERSION new file mode 100644 index 0000000..bb070ec --- /dev/null +++ b/sos-code-article1/VERSION @@ -0,0 +1,11 @@ +SOS -- Simple OS +Copyright (C) 2003,2004 The SOS Team (David Decotigny & Thomas Petazzoni) + +Version "Article 1" -- Booting + + 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. + + See the LICENSE file included in the distribution. diff --git a/sos-code-article1/bootstrap/multiboot.S b/sos-code-article1/bootstrap/multiboot.S new file mode 100644 index 0000000..4a7c65b --- /dev/null +++ b/sos-code-article1/bootstrap/multiboot.S @@ -0,0 +1,74 @@ +/* Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + + +/* The operating system is booted by Grub, so we almost have nothing + to do to boot it. We only have to conform to the Multiboot + standard, as defined by the Grub documentation */ + +#define ASM 1 +/* The multiboot.h header contains a lot of multiboot standard + definitions */ +#include "multiboot.h" + + /* The multiboot header itself. It must come first. */ +.section ".multiboot" + /* Multiboot header must be aligned on a 4-byte boundary */ + .align 4 +multiboot_header: + /* magic= */ .long MULTIBOOT_HEADER_MAGIC + /* flags= */ .long MULTIBOOT_HEADER_FLAGS + /* checksum= */ .long -(MULTIBOOT_HEADER_MAGIC \ + +MULTIBOOT_HEADER_FLAGS) + /* header_addr= */ .long multiboot_header + /* load_addr= */ .long __b_kernel + /* load_end_addr=*/ .long __e_load + /* bss_end_addr= */ .long __e_kernel + /* entry_addr= */ .long multiboot_entry + +/* Here is the beginning of the code of our operating system */ +.text + +.globl start, _start +start: +_start: +multiboot_entry: + /* Set up a stack */ + movl $(stack + MULTIBOOT_STACK_SIZE), %ebp + movl %ebp, %esp + + /* Set EFLAGS to 0 */ + pushl $0 + /* pop stack into the EFLAGS register */ + popf + + /* Push the magic and the address on the stack, so that they + will be the parameters of the cmain function */ + pushl %ebx + pushl %eax + + /* Call the cmain function (os.c) */ + call EXT_C(sos_main) + + /* Should never get there */ +loop: + hlt + jmp loop + + /* Here is the stack */ +.comm stack, MULTIBOOT_STACK_SIZE diff --git a/sos-code-article1/bootstrap/multiboot.h b/sos-code-article1/bootstrap/multiboot.h new file mode 100644 index 0000000..bee676d --- /dev/null +++ b/sos-code-article1/bootstrap/multiboot.h @@ -0,0 +1,129 @@ +#ifndef __MULTIBOOT_H__ +#define __MULTIBOOT_H__ + +/* multiboot.h - the header for Multiboot */ +/* Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Macros. */ + +/* The magic number for the Multiboot header. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* The flags for the Multiboot header. */ +#define MULTIBOOT_HEADER_FLAGS 0x00010003 + +/* The magic number passed by a Multiboot-compliant boot loader. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* The size of our stack (16KB). */ +#define MULTIBOOT_STACK_SIZE 0x4000 + +#define MULTIBOOT_CMDLINE 4 +#define MULTIBOOT_MODS 8 + +/* C symbol format. HAVE_ASM_USCORE is defined by configure. */ +#ifdef HAVE_ASM_USCORE +# define EXT_C(sym) _ ## sym +#else +# define EXT_C(sym) sym +#endif + +#ifndef ASM +/* Do not include here in boot.S. */ + + + +/* Types. */ + +/* The Multiboot header. */ +typedef struct multiboot_header +{ + unsigned long magic; + unsigned long flags; + unsigned long checksum; + unsigned long header_addr; + unsigned long load_addr; + unsigned long load_end_addr; + unsigned long bss_end_addr; + unsigned long entry_addr; +} multiboot_header_t; + +/* The symbol table for a.out. */ +typedef struct aout_symbol_table +{ + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long reserved; +} aout_symbol_table_t; + +/* The section header table for ELF. */ +typedef struct elf_section_header_table +{ + unsigned long num; + unsigned long size; + unsigned long addr; + unsigned long shndx; +} elf_section_header_table_t; + +/* The Multiboot information. */ +typedef struct multiboot_info +{ + unsigned long flags; + unsigned long mem_lower; + unsigned long mem_upper; + unsigned long boot_device; + unsigned long cmdline; + unsigned long mods_count; + unsigned long mods_addr; + union + { + aout_symbol_table_t aout_sym; + elf_section_header_table_t elf_sec; + } u; + unsigned long mmap_length; + unsigned long mmap_addr; + unsigned long drives_length; + unsigned long drives_addr; +} multiboot_info_t; + +/* The module structure. */ +typedef struct module +{ + unsigned long mod_start; + unsigned long mod_end; + unsigned long string; + unsigned long reserved; +} module_t; + +/* The memory map. Be careful that the offset 0 is base_addr_low + but no size. */ +typedef struct memory_map +{ + unsigned long size; + unsigned long base_addr_low; + unsigned long base_addr_high; + unsigned long length_low; + unsigned long length_high; + unsigned long type; +} memory_map_t; + +void dump_multiboot_info(multiboot_info_t *mbi); + +#endif /* ! ASM */ + +#endif /* __MULTIBOOT_H__ */ diff --git a/sos-code-article1/cdrom/boot/grub/menu.lst b/sos-code-article1/cdrom/boot/grub/menu.lst new file mode 100644 index 0000000..351100d --- /dev/null +++ b/sos-code-article1/cdrom/boot/grub/menu.lst @@ -0,0 +1,3 @@ +timeout 0 +title Simple OS +kernel /sos.elf diff --git a/sos-code-article1/cdrom/boot/grub/stage2_eltorito b/sos-code-article1/cdrom/boot/grub/stage2_eltorito Binary files differnew file mode 100644 index 0000000..6d82f08 --- /dev/null +++ b/sos-code-article1/cdrom/boot/grub/stage2_eltorito diff --git a/sos-code-article1/cdrom/sos.elf b/sos-code-article1/cdrom/sos.elf Binary files differnew file mode 100755 index 0000000..9dcfd43 --- /dev/null +++ b/sos-code-article1/cdrom/sos.elf diff --git a/sos-code-article1/drivers/bochs.c b/sos-code-article1/drivers/bochs.c new file mode 100644 index 0000000..db18599 --- /dev/null +++ b/sos-code-article1/drivers/bochs.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <hwcore/ioports.h> +#include <sos/klibc.h> + +#include "bochs.h" + +/* This is a special hack that is only useful when running the + operating system under the Bochs emulator. */ +#define SOS_BOCHS_IOPORT 0xe9 + +sos_ret_t sos_bochs_setup(void) +{ + return SOS_OK; +} + + +#define sos_bochs_putchar(chr) \ + outb((chr), SOS_BOCHS_IOPORT) + +sos_ret_t sos_bochs_putstring(const char* str) +{ + for ( ; str && (*str != '\0') ; str++) + sos_bochs_putchar(*str); + + return SOS_OK; +} + + +sos_ret_t sos_bochs_puthex(unsigned val, int nbytes) +{ + unsigned c; + +#define BOCHS_PRTHEX(q) \ + ({ unsigned char r; if ((q) >= 10) r='a'+(q)-10; \ + else r='0'+(q); sos_bochs_putchar(r); }) + + switch (nbytes) + { + case 4: + c = (val >> 24) & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + case 3: + c = (val >> 16) & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + case 2: + c = (val >> 8) & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + case 1: + c = val & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + } + + return SOS_OK; +} + + +sos_ret_t sos_bochs_hexdump(const void* addr, int nbytes) +{ + int offs; + for (offs = 0 ; offs < nbytes ; offs++) + { + const unsigned char *c; + + if ((offs % 16) == 0) + { + sos_bochs_putstring("0x"); + sos_bochs_puthex(offs, 4); + } + + if ((offs % 8) == 0) + sos_bochs_putstring(" "); + + c = (const unsigned char*)(addr + offs); + sos_bochs_puthex(*c, 1); + sos_bochs_putstring(" "); + + if (((offs + 1) % 16) == 0) + sos_bochs_putstring("\n"); + } + + if (offs % 16) + sos_bochs_putstring("\n"); + + return SOS_OK; +} + + +sos_ret_t sos_bochs_printf(const char *format, /* args */...) +{ + char buff[256]; + va_list ap; + + va_start(ap, format); + vsnprintf(buff, sizeof(buff), format, ap); + va_end(ap); + + return sos_bochs_putstring(buff); +} diff --git a/sos-code-article1/drivers/bochs.h b/sos-code-article1/drivers/bochs.h new file mode 100644 index 0000000..310b023 --- /dev/null +++ b/sos-code-article1/drivers/bochs.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_BOCHS_H_ +#define _SOS_BOCHS_H_ + +/** + * @file bochs.h + * + * If you compiled Bochs with the --enable-e9-hack, then any character + * printed to the 0xE9 I/O port is printed to the xterm that is + * running Bochs. This may appear to be a detail, but in fact, this + * functionnality is *VERY* precious for debugging purposes. This + * """driver""" handles this feature. + */ + +#include <sos/errno.h> +#include <sos/types.h> + +sos_ret_t sos_bochs_setup(void); + +sos_ret_t sos_bochs_putstring(const char* str); + +/** Print the least signficant 32 (nbytes == 4), 24 (nbytes == 3), 16 + (nbytes == 2) or 8 (nbytes == 1) bits of val in hexadecimal. */ +sos_ret_t sos_bochs_puthex(unsigned val, int nbytes); + +/** hexdump-style pretty printing */ +sos_ret_t sos_bochs_hexdump(const void* addr, int nbytes); + +/** + * Print the formatted string. Very restricted version of printf(3): + * 1/ can print max 255 chars, 2/ supports only %d/%i, %c, %s, %x + * without any support for flag charachters (eg %08x). + */ +sos_ret_t sos_bochs_printf(const char *format, /* args */...) + __attribute__ ((format (printf, 1, 2))); + +#endif diff --git a/sos-code-article1/drivers/x86_videomem.c b/sos-code-article1/drivers/x86_videomem.c new file mode 100644 index 0000000..cc4b79c --- /dev/null +++ b/sos-code-article1/drivers/x86_videomem.c @@ -0,0 +1,128 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <sos/klibc.h> +#include <hwcore/ioports.h> + +#include "x86_videomem.h" + +/* The text video memory starts at address 0xB8000. Odd bytes are the + ASCII value of the character, even bytes are attribute for the + preceding character. */ +#define VIDEO 0xb8000 + + +/* Console screen size */ +#define LINES 25 +#define COLUMNS 80 + + +/** The structure of a character element in the video memory. @see + http://webster.cs.ucr.edu/AoA DOS edition chapter 23 */ +typedef struct { + unsigned char character; + unsigned char attribute; +} __attribute__ ((packed)) x86_video_mem[LINES*COLUMNS]; + + + +/** The base pointer for the video memory */ +static volatile x86_video_mem *video = (volatile x86_video_mem*)VIDEO; + +sos_ret_t sos_x86_videomem_setup(void) +{ + /* + * Hide cursor. @see Ralf Brown's interrupt (and port) list + * http://www-2.cs.cmu.edu/~ralf/files.html + */ +#define CRT_REG_INDEX 0x3d4 +#define CRT_REG_DATA 0x3d5 + + /* CRT index port => ask for access to register 0xa ("cursor + start") */ + outb(0x0a, CRT_REG_INDEX); + + /* (RBIL Tables 708 & 654) CRT Register 0xa => bit 5 = cursor OFF */ + outb(1 << 5, CRT_REG_DATA); + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_cls(unsigned char attribute) +{ + /* Clears the screen */ + int i; + for(i = 0 ; i < LINES*COLUMNS ; i++) + { + (*video)[i].character = 0; + (*video)[i].attribute = attribute; + } + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_putstring(unsigned char row, unsigned char col, + unsigned char attribute, + const char *str) +{ + unsigned video_offs = row*COLUMNS + col; + + if (video_offs >= LINES*COLUMNS) + return -SOS_EINVAL; + + for ( ; str && *str && (video_offs < LINES*COLUMNS) ; str++, video_offs++) + { + (*video)[video_offs].character = (unsigned char)*str; + (*video)[video_offs].attribute = attribute; + } + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_putchar(unsigned char row, unsigned char col, + unsigned char attribute, + unsigned char c) +{ + unsigned video_offs = row*COLUMNS + col; + + if (video_offs >= LINES*COLUMNS) + return -SOS_EINVAL; + + (*video)[video_offs].character = c; + (*video)[video_offs].attribute = attribute; + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_printf(unsigned char row, unsigned char col, + unsigned char attribute, + const char *format, /* args */...) +{ + char buff[256]; + va_list ap; + + va_start(ap, format); + vsnprintf(buff, sizeof(buff), format, ap); + va_end(ap); + + return sos_x86_videomem_putstring(row, col, attribute, buff); +} diff --git a/sos-code-article1/drivers/x86_videomem.h b/sos-code-article1/drivers/x86_videomem.h new file mode 100644 index 0000000..31a9dfc --- /dev/null +++ b/sos-code-article1/drivers/x86_videomem.h @@ -0,0 +1,98 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_X86_VIDEOMEM_H_ +#define _SOS_X86_VIDEOMEM_H_ + +/** + * @file x86_videomem.h + * + * On x86 PC platforms, the text mode screen memory (and CGA/EGA/VGA + * too) is mapped into physical memory. This file handles access to + * this screen, supposed to be set in text-mode, through this memory + * area. All the functions below print the characters directly to the + * memory, without interpreting the escaped characters (such as \n, + * \r...) + */ + +#include <sos/errno.h> + +/** + * x86 video attributes + * See http://webster.cs.ucr.edu/AoA/DOS/ch23/CH23-1.html + */ +/* Normal and Dark/Light foreground */ +#define SOS_X86_VIDEO_FG_BLACK 0 +#define SOS_X86_VIDEO_FG_DKGRAY 8 +#define SOS_X86_VIDEO_FG_BLUE 1 +#define SOS_X86_VIDEO_FG_LTBLUE 9 +#define SOS_X86_VIDEO_FG_GREEN 2 +#define SOS_X86_VIDEO_FG_LTGREEN 10 +#define SOS_X86_VIDEO_FG_CYAN 3 +#define SOS_X86_VIDEO_FG_LTCYAN 11 +#define SOS_X86_VIDEO_FG_RED 4 +#define SOS_X86_VIDEO_FG_LTRED 12 +#define SOS_X86_VIDEO_FG_MAGENTA 5 +#define SOS_X86_VIDEO_FG_LTMAGENTA 13 +#define SOS_X86_VIDEO_FG_BROWN 6 +#define SOS_X86_VIDEO_FG_YELLOW 14 +#define SOS_X86_VIDEO_FG_LTGRAY 7 +#define SOS_X86_VIDEO_FG_WHITE 15 +/* Background */ +#define SOS_X86_VIDEO_BG_BLACK (0 << 4) +#define SOS_X86_VIDEO_BG_BLUE (1 << 4) +#define SOS_X86_VIDEO_BG_GREEN (2 << 4) +#define SOS_X86_VIDEO_BG_CYAN (3 << 4) +#define SOS_X86_VIDEO_BG_RED (4 << 4) +#define SOS_X86_VIDEO_BG_MAGENTA (5 << 4) +#define SOS_X86_VIDEO_BG_BROWN (6 << 4) +#define SOS_X86_VIDEO_BG_LTGRAY (7 << 4) +/* Blinking */ +#define SOS_X86_VIDEO_FG_BLINKING (1 << 7) + + +/** Setup the video RAM mapping and clear the screen */ +sos_ret_t sos_x86_videomem_setup(void); + +/** Clears the screen and set the background color as given by + attribute */ +sos_ret_t sos_x86_videomem_cls(unsigned char attribute); + +/** Print the string on the scren with the given attribute. Does not + handle scrolling */ +sos_ret_t sos_x86_videomem_putstring(unsigned char row, unsigned char col, + unsigned char attribute, + const char *str); + +/** Print the character on the scren with the given attribute. Does not + handle scrolling */ +sos_ret_t sos_x86_videomem_putchar(unsigned char row, unsigned char col, + unsigned char attribute, + unsigned char c); + +/** + * Print the formatted string. Very restricted version of printf(3): + * 1/ can print max 255 chars, 2/ supports only %d/%i, %c, %s, %x + * without any support for flag charachters (eg %08x). + */ +sos_ret_t sos_x86_videomem_printf(unsigned char row, unsigned char col, + unsigned char attribute, + const char *format, /* args */...) + __attribute__ ((format (printf, 4, 5))); + +#endif /* _SOS_X86_VIDEOMEM_H_ */ diff --git a/sos-code-article1/extra/Makefile b/sos-code-article1/extra/Makefile new file mode 100644 index 0000000..f858aa6 --- /dev/null +++ b/sos-code-article1/extra/Makefile @@ -0,0 +1,40 @@ +OBJCOPY=objcopy + +all: sos_qemu.img + +-include ../.mkvars + +# The image is the simple concatenation of the boot sector and the kernel +# It may be use in bochs or on a real floppy, but NOT in qemu (see below) +sos_bsect.img: bsect.bin sos.bin + cat $^ > $@ + @echo "[31mYou can use the $@ image in bochs or on a real floppy (NOT qemu)[m" + +# For qemu, the trick is to tell it we have *more* than 1440 sectors (720kB). +# Rtherwise the qemu disk geometry will be configured to be that of a 720kB +# floppy, while our boot sector assumes it to be 1.44MB +sos_qemu.img: sos_bsect.img + # Padding with 0s after the bsect/kernel image + cat $< /dev/zero | dd of=$@ bs=1k count=1440 + @echo "[31mYou can use the $@ image in qemu, bochs, or on a real floppy[m" + +# we extract the boot sector from the main ELF binary +bsect.bin: sos_bsect.elf + $(OBJCOPY) -v -O binary -j .bootsect $< $@ + +# we extract the kernel code from the main ELF binary +sos.bin: sos_bsect.elf + $(OBJCOPY) -v -O binary -R .bootsect $< $@ + +# The main ELF binary contains the boot sector and the kernel code +# linked together (hence we deal with a SINGLE image that we split +# above) because they share some symbol definitions +sos_bsect.elf: bootsect.o compile_kernel + $(LD) --warn-common -T ./sos_bsect.lds -o $@ \ + bootsect.o $(wildcard ../hwcore/*.o ../drivers/*.o ../sos/*.o) + +compile_kernel: + $(MAKE) -C .. + +clean: + $(RM) *.img *.elf *.bin *~ *.o *.out diff --git a/sos-code-article1/extra/README b/sos-code-article1/extra/README new file mode 100644 index 0000000..0272f1f --- /dev/null +++ b/sos-code-article1/extra/README @@ -0,0 +1,73 @@ + +Contents of the extra/ directory +================================ + +Data and configuration files to support generation of sos on non-x86 +and/or grub-less hosts: + - dot.mkvars: file to copy as .mkvars in the root directory to + compile on a non-x86 host, and to generate the grub floppy image on + a grub-less host + - grub.img.gz: compressed image of a Grub floppy (without any + kernel). Used by dot.mkvars. + - mtoolsrc: file needed by .mkvars to compile a the floppy image + +Support of a sos-specific boot sector: + - Makefile: rules to compile sos_bsect.img, the floppy image with the + boot sector and the Sos + - bootsect.S: x86 Sos boot sector (GNU as). Depends on sos_bsect.lds + - sos_bsect.lds: ld script to bind the boot sector with the remaining + of the kernel + +Misc: + - qemu-port-e9.diff: patch over qemu to support the bochs "port 0xe9 hack" + + +What you can do with these files +================================ + + +*** Compile SOS from another architecture: +------------------------------------------ + - compile a cross-compiler for the i586-gnu target. This involves + compiling the binutils and gcc. Here are example configuration + options for them: + binutils (replace sparc-cun-solaris with your arch): + ../binutils-2.13/configure --prefix=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/stow/binutils-2.11 --host=sparc-sun-solaris2.7 i586-gnu + make && make install + gcc (ditto): + CFLAGS="-O2 -Dinhibit_libc" ../gcc-3.2/configure --target=i586-gnu --prefix=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/stow/gcc-3.2 --with-as=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/bin/as --with-ld=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/bin/ld --with-gnu-as --with-gnu-ld --enable-languages=c --disable-shared --disable-multilib --disable-nls --enable-threads=single + make && make install + - compile the mtools + - copy dot.mkvars to the root directory of SOS, as ".mkvars" + - customize the CC/LD/... variables to suit your cross-compiler + installatioon + - now you may run make from the SOS root directory, it should + generate the Grub boot floppy image. The following warning is + normal: + .mkvars:16: attention : écrasement des commandes pour la cible « grub-sos.img » + Makefile:92: attention : anciennes commandes ignorées pour la cible « grub-sos.img » + + +*** To compile SOS from an x86 where grub is not or incorrectly installed: +-------------------------------------------------------------------------- + - copy dot.mkvars to the root directory of SOS, as ".mkvars" + - customize the CC/LD/... variables to suit your cross-compiler + installatioon + - now you may run make from the SOS root directory, it should + generate the Grub boot floppy image. The following warning is + normal: + .mkvars:16: attention : écrasement des commandes pour la cible « grub-sos.img » + Makefile:92: attention : anciennes commandes ignorées pour la cible « grub-sos.img » + + +*** To compile SOS with its own bootloader: +------------------------------------------- + - for cross-architecture compilation: see above + - cd to this extra/ directory + - run 'make' + - the floppy image is: sos_bsect.img + NOTE : SOS will not boot correctly this way after article 2 ! + + +-- +David Decotigny diff --git a/sos-code-article1/extra/bootsect.S b/sos-code-article1/extra/bootsect.S new file mode 100644 index 0000000..f01ca20 --- /dev/null +++ b/sos-code-article1/extra/bootsect.S @@ -0,0 +1,393 @@ + +/* + * @(#) $Id: bootsect.S,v 1.6 2004/06/18 07:43:51 d2 Exp $ + * Description : Bootsecteur en syntaxe AT&T + * Auteurs : Thomas Petazzoni & Fabrice Gautier & Emmanuel Marty + * Jerome Petazzoni & Bernard Cassagne & coffeeman + * David Decotigny + * Bug reports to kos-misc@enix.org + */ + +/* + * But global de ce bootsecteur : + * + * - Initialiser la becane + * - Charger le kernel + * - Passer en mode protege + * - Executer le kernel + * + * Taille restante : Je vous rappelle qu'un bootsecteur ne peut faire + * qu'au maximum 512 octets dont 2 octets obligatoires 0xAA55. Sur + * les 510 octets reellement utilisables, il reste 3 octets dispo (60 + * si on decide d'enlever le BPB un jour) !!! + * + * thomas_petazzoni : - detection des codes d'erreurs de chargement + * David_Decotigny : - Passage en GNU as + * David_Decotigny : - Chargement du noyau au-dela du 1er Mega (taille + * max = 0x9e000 octets = 632ko), pour avoir le + * meme noyau sous grub et avec le bootsecteur + */ + + /* + * Sequence d'operations : + * - Le BIOS charge le bootsect en 0x7c00 (BOOT_ADRESS). On choisit + * la representation 0x7c0:0000 pour que le .org 0 reste valide + * - Le bootsect se deplace de lui-meme en 0x9f000 (COPY_ADRESS). On + * choisit la representation 0x9f00:0000 pour que le .org 0 reste + * valide + * - Le bootsect verifie que le processeur est du type 386+ + * - Il charge le noyau depuis la disquette en memoire a partir de + * 0x1000 (LOAD_ADRESS). Le noyau peut au max tenir sur + * SECTORS_TO_LOAD secteurs + * - Il passe en pmode flat (apres ouverture a20) + * - Il recopie le noyau (situe en LOAD_ADRESS) vers son adresse + * finale (FINAL_ADDRESS = 2Mo). La recopie se fait sur tout l'espace + * LOAD_ADRESS ---> COPY_ADRESS, c'est a dire sur 0x9e000 octets = + * 632ko. Le noyau peut donc au max faire 632ko. Le nombre max de + * secteurs de disquette qu'on peut charger est donc 1264 + */ + + +/* La taille de la pile */ +#define BOOT_STACK_SIZE 0x4000 + + .file "bootsect.S" + + /* Tout est place dans une seule section */ + .section ".bootsect" + + /* L'essentiel du bootsector (sauf les 1eres instructions) + sont a un offset 0. On fait en sorte que le compilo soit + d'accord la-dessus. Quand on a des adresse realm exotiques + (0x7c00, 0x9f000, ...), on s'arrange toujours pour avoir un + offset de 0 => on choisira le segment adapte (0x7c0, + 0x9f00, ...). Il ne faut pas oublier le ld -Ttext 0 */ + .org 0 + + /* Pour que gas genere du 16bits, afin que ca marche en realm */ + .code16 + +#define SECTORS_TO_LOAD 128 /* 64 ko */ /* MAX=1264 */ + +/* + * Parametres de la disquette. Comme c'est chiant de faire une + * procedure de detection auto, et que ca prend de la place, on fait + * ca "a la main". Par exemple, une DD 720 Ko a 9 secteurs/piste, une + * 1.44 Mo a 18 secteurs/pistes + */ +#define CYLS 80 +#define HEADS 1 +#define SECTS 18 + +#define BOOT_ADRESS 0x07C00 /* Adresse de demarrage (lineaire) */ +#define BOOT_SEG (BOOT_ADRESS>>4) /* Segment de Boot */ +#define BOOT_SIZE 512 /* Taille bu bootsecteur */ +#define COPY_ADRESS 0x9F000 /* La ou on va copier le + bootsecteur (lineaire) */ +#define COPY_SEG (COPY_ADRESS>>4) /* Segment de la ou on va + copier le bootsecteur */ +#define LOAD_ADRESS 0x01000 /* 1er chargement du systeme */ +#define LOAD_SEG (LOAD_ADRESS>>4) /* Segment du 1er chargement du */ +#define MAX_KERN_LEN COPY_ADRESS-LOAD_ADRESS /* Taille noyau maxi */ + +/* IMPORTANT : Cette valeur DOIT etre identique a l'adresse presente + dans sos.lds ! */ +#define FINAL_ADDRESS 0x200000 /* Adresse finale (physique de 0 a 4G) + ou est charge le noyau */ + +#define OP16 .byte 0x66 ; +#define OP32 .byte 0x66 ; + +/* + * Procedure qui vide le buffer clavier. + */ +#define WAITKB \ + 1: ;\ + .word 0xeb ;\ + .word 0xeb ;\ + inb $0x64, %al ;\ + andb $0x2, %al ;\ + jnz 1b + + /* Le point d'entree dans le bootsect */ +.globl _bsect +_bsect: + + /* + * La portion qui suit est situee a un offset 0x7c00 en + * memoire. Attention donc aux references memoire dans cette + * partie. On choisit de rester en offset 0 (.org 0), mais on + * charge correctement les segments a 0x7c0. + */ + + movw $BOOT_SEG, %ax /* le bootsecteur est a 0x7C00 en lineaire */ + movw %ax, %ds /* on le copie a l'adresse COPY_ADRESS */ + xorw %si, %si /* comme cette adresse est la plus haute de la mem */ + xorw %di, %di /* on pourra charger un kernel + gros */ + movw $(BOOT_SIZE>>1), %cx + movw $COPY_SEG, %ax + movw %ax, %es + cld + rep ; movsw + + /* on continue a executer le bootsecteur, mais maintenant a + partir de 0x9F000, qu'on represente sous la forme + 0x9f00:offset */ + ljmp $COPY_SEG, $here + + /* + * A partir de maintenant, on est a un offset 0 en memoire + * (segment 0x9f00), conformement a ce que veut le compilo. + */ +here: + movw %ax, %ds + + /* Petite pile temporaire (1k - 3.84k en RAM ; les adresses 0-1k + correspondent au vecteur d'interruptions). */ + movw %ax, %ss + movw $(LOAD_ADRESS - 0x10), %sp + + /* Efface l'ecran */ + movb $0x0, %ah + movb $0x3, %al + int $0x10 + + /* Affiche les messages d'attente */ + movw $loadkern, %si + call message + movw $check, %si + call message + +check386: + /* + * la attention, plus complexe : on teste si le proc est un + * 386+ pour cela, on va essayer de modifier les bits 12 ? 14 + * du registre E-flag si la modification reste, alors le proc + * est un 386+, sinon, c'est =< 286 + * + * Merci a Emmanuel Marty pour la compatibilite avec les 386 + * "pre-jurassique" + */ + + pushf /* on sauvegarde le E-Flag */ + movb $0x70, %ah + pushw %ax + popf + pushf + popw %ax + orb %ah, %ah + je no386 /* si la modif n'est pas valable, alors on saute a + no386 */ + popf /* on les restaure ? la fin ... */ + + /* Message de confirmation de 386+ et d'attente */ + movw $found386, %si + call message + movw $loading, %si + call message + +/* Copie du noyau disquette => RAM a partir de 0x1000 + L'adresse de destination est définie par es:0, où es vaut + initialement 0x100 (ie correspond alors à l'adresse 256*16, soit 4 + ko). Chaque itération incrémente ce registre es de 32, ce qui + correspond à un bond de 32*16 en mémoire, soit la taille d'un + secteur. De cette façon, puisqu'on joue sur les segments plutôt que + sur les offsets, la taille du noyau n'est pas limitée à 64 ko. Elle + est limitée par contre à la taille de la mémoire disponible sous + les 1Mo, \ie 640 ko (0x9f000 - 0x1000). */ +copyKernel: + /* Chargement du noyau en LOAD_SEG:0 */ + /* 3 iterateurs : + - load_size : le nbre de secteurs a charger + - cl : le secteur ou on en est pour le + cylindre en cours (<= SECTS) + - dh : la tete en cours (0/1) + */ + movb $0, %dl + movw $LOAD_SEG, %ax + movw %ax, %es + + xorw %bx, %bx + xorw %dx, %dx + movw $1, %cx /* premier secteur */ + +.nextsector: /* prochain secteur */ + incb %cl /* en incrementant CL */ + cmpb $SECTS, %cl /* si CL =< SECTS (=nbre de secteurs/pistes) + alors on charge */ + jbe .sector + movb $1, %cl /* sinon on revient au secteur 1 */ + incb %dh /* mais sur l'autre tete */ + cmpb $1, %dh /* on recompare, si DH =< 1 */ + je .sector /* on charge */ + movb $0, %dh /* sinon on repasse a la tete 0 */ + incb %ch /* mais on change de cylindre */ + +.sector: + pushw %es + movw $0x0201, %ax /* service 0x2, chargement 0x1 seecteur */ + int $0x13 /* Go ! */ + jc halt /* erreur */ + popw %ax + addw $32, %ax /* on a charge un secteur, donc on doit + charger 512 bytes plus loin */ + movw %ax, %es /* on avance donc le segment du buffer de + 32bytes, ie 1 secteur en RAM (car 32*16=512) */ + + movw $(0x0E*256+'.'), %ax /* affiche un point */ + int $0x10 + + decw (load_size) /* et on repart pour le prochain secteur + tant qu'on n'a pas fini ! */ + jnz .nextsector + +after: + movw $0x03f2, %dx + inb %dx, %al /* stoppe le moteur */ + andb $0x0f, %al + outb %al, %dx + + cli /* on interdit les interruptions */ + +fincopie: + pushw %cs + popw %ds + + /* on ouvre la porte A20 */ + WAITKB /* on vide le buffer */ + movb $0xd1, %al /* on met a jour le port */ + outb %al, $0x64 + WAITKB + movb $0xdf, %al /* bit 2 = ouverture/fermeture */ + outb %al, $0x60 + + /* + * init gdt + */ +InitGDT: + /* Préparation du flat mode */ + lgdt gdtr + +GoPMode: + /* Passage en mode protégé */ + movl %cr0, %eax + orb $1, %al /* set PE bit to 1 */ + movl %eax, %cr0 + + /* we are not yet in Pmode jump 'in' pmode clearing prefetch + * queue and loading a new selector */ + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + +/* + * Code 32 bits ============================================================ + */ + .code32 + +JumpToHere32: /* Se deplace a l'endroit actuel, en passant en 32bits + et en utilisant la gdt, et vide la prefetch queue */ + .byte 0x66 /* Prefixe 32bits : en realite, jusqu'au jmp, on est + encore en 16 bits */ + ljmp $0x8, $(COPY_ADRESS+(Here32)) +Here32: + /* Et voila : On est en 32 bits vrai */ + +MoveKernelToFinalAddr: /* Deplace le noyau (en LOAD_ADDRESS) vers sa + destination finale (FINAL_ADDRESS) */ + movl $0x10, %eax + movl %eax, %ds /* Seg Src = DSeg */ + movl %eax, %es /* Sed Dest = DSeg */ + cld + movl $LOAD_ADRESS, %esi /* On commence la copie au debut du noyau */ + movl $FINAL_ADDRESS, %edi /* On copie vers cette adresse */ + movl $MAX_KERN_LEN, %ecx /* Taille recopie */ + shrl $2, %ecx + rep + movsl + +LaunchKernel: + /* Met en place une pile au niveau du symbole "stack" */ + movl %eax, %ss + movl $(stack + BOOT_STACK_SIZE), %ebp + movl %ebp, %esp + + /* Saut vers le noyau. La GDT est en place (flat mode), les + * selecteurs aussi, a20 est ouverte, et les interruptions sont + * cli + pas de idt. Le PIC n'est pas programme */ + ljmp $0x8, $sos_main + +/* + * Utilities ============================================================ + */ + .code16 + +message: + lodsb /* charge ds:si dans al et incremente si */ + orb %al, %al /* si al = 0 */ + jz 1f + movb $0x0e, %ah /* service 0Eh (affichage d'un caractere) */ + movw $0x0007, %bx /* Parametres : blanc sur fond noir */ + int $0x10 /* Appel de l'interruption 10h */ + jmp message /* On repart au début ... */ + 1: ret /* si la chaine est finie alors on retourne + dans la fonction appelante */ + +halt: + pushw %cs + popw %es + movw $haltmsg, %si + call message + cli + 1: jmp 1b + ret + +no386: + movw $need386, %si + call message + call halt + + /* + * GDT + */ + +gdt: +gdtr: +NULL_Desc: + .word (EndGDT)-(gdt)-1 /* Taille GDT */ + .long (gdt)+COPY_ADRESS +unused: + .word 0 + +CS_Desc: /* 0x8 */ + .word 0xFFFF, 0 + .byte 0, 0x9B, 0xCF, 0 + +DS_Desc: /* 0x10 */ + .word 0xFFFF, 0 + .byte 0, 0x93, 0xCF, 0 + +EndGDT: + + /* quelques messages */ + +loadkern: .string "-= S O S =- : The Simple Operating System \r\n" +check: .string "Checking for a 386+ processor... " +found386: .string " [OK]\r\n" +need386: .string " [FAILED]\r\n" +diskerror: .string "Disk Error\r\n" +loading: .string "Loading... " +haltmsg: .string "System Halted\r\n" + +/*** Les code/données du boot secteur se terminent ICI. le marqueur de + * fin (aa55) est ajouté automatiquement par le script ld + * sos_bsect.lds ***/ + +/* La pile de 16k qu'on utilise au niveau de LaunchKernel se trouve + declaree avec le noyau, dans sa section ".bss", cad HORS du boot + secteur ! (sinon ca depasserait 512B, forcément). On aurait pu la + définir directement dans le sos_bsect.lds, ou dans un fichier .c + auxiliaire pour plus de clarté */ +.comm stack, BOOT_STACK_SIZE diff --git a/sos-code-article1/extra/dot.mkvars b/sos-code-article1/extra/dot.mkvars new file mode 100644 index 0000000..1f7dca5 --- /dev/null +++ b/sos-code-article1/extra/dot.mkvars @@ -0,0 +1,29 @@ +# For cross-compilation and/or installations without grub available, +# copy this file as .mkvars to the root directory of the SOS sources, +# and customize the CC/LD/... variables. You still need the mtools +# installed and running + +CC := i586-gnu-gcc +LD := i586-gnu-ld +OBJCOPY := i586-gnu-objcopy +CFLAGS += -O3 + +# Configuration of mtools +MTOOLSRC = extra/mtoolsrc +export MTOOLSRC + +$(MULTIBOOT_IMAGE): $(KERNEL_OBJ) menu.txt + gzip -dc < extra/grub.img.gz > $@ + mcopy menu.txt v:/boot/grub/ + mmd v:/system + mcopy sos.elf v:/system/sos.elf + +menu.txt: + echo timeout 0 > $@ + echo default 0 >> $@ + echo title SOS >> $@ + echo "root (fd0)" >> $@ + echo kernel /system/sos.elf >> $@ + +runbochs: all + echo c | bochs -q diff --git a/sos-code-article1/extra/grub.img.gz b/sos-code-article1/extra/grub.img.gz Binary files differnew file mode 100644 index 0000000..4f98e74 --- /dev/null +++ b/sos-code-article1/extra/grub.img.gz diff --git a/sos-code-article1/extra/mtoolsrc b/sos-code-article1/extra/mtoolsrc new file mode 100644 index 0000000..df1a26e --- /dev/null +++ b/sos-code-article1/extra/mtoolsrc @@ -0,0 +1,2 @@ +# For older versions of mtools, you may have to remove "filter" +drive v: file="fd.img" 1.44M filter diff --git a/sos-code-article1/extra/qemu-port-e9.diff b/sos-code-article1/extra/qemu-port-e9.diff new file mode 100644 index 0000000..d8be044 --- /dev/null +++ b/sos-code-article1/extra/qemu-port-e9.diff @@ -0,0 +1,73 @@ +--- Makefile.target 17 Mar 2004 23:46:04 -0000 1.19 ++++ Makefile.target 18 Mar 2004 14:20:29 -0000 +@@ -217,7 +217,8 @@ + # must use static linking to avoid leaving stuff in virtual address space + VL_OBJS=vl.o osdep.o block.o monitor.o \ + ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ +- fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o ++ fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o \ ++ port-e9.o + ifeq ($(TARGET_ARCH), ppc) + VL_OBJS+= hw.o + endif +--- hw/pc.c 14 Mar 2004 21:46:48 -0000 1.2 ++++ hw/pc.c 18 Mar 2004 14:20:29 -0000 +@@ -371,6 +371,7 @@ + SB16_init(); + + fdctrl_init(6, 2, 0, 0x3f0, fd_table); ++ port_e9_init(); + + cmos_init(ram_size, boot_device); + } +--- /dev/null 2003-01-30 11:24:37.000000000 +0100 ++++ port-e9.c 2004-03-18 15:18:52.660493187 +0100 +@@ -0,0 +1,38 @@ ++/* ++ * QEMU Port 0xe9 hack ++ * ++ * Copyright (c) 2000-2004 E. Marty, the bochs team, D. Decotigny ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++#include <stdio.h> ++#include <unistd.h> ++#include <inttypes.h> ++ ++#include "vl.h" ++ ++static void bochs_e9_write(void *opaque, uint32_t address, uint32_t data) ++{ ++ write(fileno(stdout), &data, 1); ++} ++ ++void port_e9_init () ++{ ++ register_ioport_write(0xe9, 1, 1, bochs_e9_write, NULL); ++} +--- vl.h 17 Mar 2004 23:17:16 -0000 1.14 ++++ vl.h 18 Mar 2004 14:29:06 -0000 +@@ -268,4 +268,7 @@ + void term_flush(void); + void term_print_help(void); + ++/* port-e9.c */ ++void port_e9_init(void); ++ + #endif /* VL_H */ diff --git a/sos-code-article1/extra/sos_bsect.lds b/sos-code-article1/extra/sos_bsect.lds new file mode 100644 index 0000000..ac42f23 --- /dev/null +++ b/sos-code-article1/extra/sos_bsect.lds @@ -0,0 +1,61 @@ +/* Copyright (C) 2004, David Decotigny + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +SECTIONS +{ + /* *********************************************** + * The bootsector is here. We link it against the remaining of the kernel + * in order to automatically figure out its size that must be loaded + * from file to memory (see the load_size definition below) + */ + + /* If we use one, we put the boot sector here. We don't set its + * address to 0x7c000 (aka 0x7c00:0), since it reloads itself to + * 0x9f000, causing the 0x7c000 address to be meaningless too. So we + * chose to pretend that the address is 0x0, and to make a little + * address arithmetic in bootsect.S */ + .bootsect 0x0 : + { + /* The code for the boot sector goes here */ + *(.bootsect); + + /* The load_size symbol contains the size of the area (in + * sectors, aka 512 Bytes) that the boot sector should copy from + * the disk. The bss section is not included since it uses 0 + * bytes on disk */ + load_size = .; + LONG((__e_load - __b_load + 511) >> 9); + /* ---> This is equivalent to ceil( (__e_load - __b_load) / 512 ) */ + + /* At offsets 511 and 512, we set the boot sector signature (AA55h) */ + . = 0x1fe; + SHORT(0xAA55); + } +} + + +/* This is to avoid a cut/paste here. Please notice that a multiboot + * section WILL be inserted, which is NOT mandatory (we could have + * removed it without getting into trouble). Please note however that + * the *.bin files will NOT be multiboot compatible (they are not in ELF + * format): they are expected to be directly booted by the BIOS (or + * by the "chainloader" command of Grub). */ +INCLUDE ../support/sos.lds + +/* We overload the entry set in sos.lds, just to avoid an ld warning */ +ENTRY(sos_main); diff --git a/sos-code-article1/hwcore/ioports.h b/sos-code-article1/hwcore/ioports.h new file mode 100644 index 0000000..443acb7 --- /dev/null +++ b/sos-code-article1/hwcore/ioports.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2004 All GPL'ed OS + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_IOPORTS_H_ +#define _SOS_IOPORTS_H_ + +/** + * @ioports.h + * + * Intel-specific I/O space access routines. + */ + +/* This macro allows to write to an I/O port */ +#define outb(value, port) \ + __asm__ volatile ( \ + "outb %b0,%w1" \ + ::"a" (value),"Nd" (port) \ + ) \ + +// read one byte from port +#define inb(port) \ +({ \ + unsigned char _v; \ + __asm__ volatile ( \ + "inb %w1,%0" \ + :"=a" (_v) \ + :"Nd" (port) \ + ); \ + _v; \ +}) + +#endif /* _SOS_IOPORTS_H_ */ diff --git a/sos-code-article1/sos.elf b/sos-code-article1/sos.elf Binary files differnew file mode 100755 index 0000000..9dcfd43 --- /dev/null +++ b/sos-code-article1/sos.elf diff --git a/sos-code-article1/sos.map b/sos-code-article1/sos.map new file mode 100644 index 0000000..3ba39c3 --- /dev/null +++ b/sos-code-article1/sos.map @@ -0,0 +1,33 @@ +00201000 __b_kernel +00200000 __b_load +00205c00 __e_kernel +00201bfb __e_load +00201011 loop +0020157f memcmp +00201528 memcpy +00201559 memset +00201000 multiboot_entry +00200000 multiboot_header +00201a9f snprintf +0020141d sos_bochs_hexdump +002014e2 sos_bochs_printf +0020123f sos_bochs_puthex +0020121a sos_bochs_putstring +00201210 sos_bochs_setup +00201ad4 sos_main +00201034 sos_x86_videomem_cls +0020117e sos_x86_videomem_printf +00201107 sos_x86_videomem_putchar +00201077 sos_x86_videomem_putstring +00201014 sos_x86_videomem_setup +00201c00 stack +00201000 start +00201000 _start +002016cd strcmp +002015d9 strlen +0020170f strncmp +002015fe strnlen +00201682 strzcat +00201631 strzcpy +00201b80 video +00201770 vsnprintf diff --git a/sos-code-article1/sos/assert.h b/sos-code-article1/sos/assert.h new file mode 100644 index 0000000..a14ca0b --- /dev/null +++ b/sos-code-article1/sos/assert.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2004 The KOS Team + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_ASSERT_H_ +#define _SOS_ASSERT_H_ + +#include <drivers/bochs.h> +#include <drivers/x86_videomem.h> + +/** + * If the expr is FALSE, print a message and halt the machine + */ +#define SOS_ASSERT_FATAL(expr) \ + ({ \ + int __res=(int)(expr); \ + if (! __res) { \ + asm("cli\n"); /* disable interrupts -- x86 only */ \ + sos_bochs_printf("%s@%s:%d Assertion " # expr " failed\n", \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + sos_x86_videomem_printf(24, 0, 12, \ + "%s@%s:%d Assertion " # expr " failed", \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + for (;;) asm("hlt;") ; /* Infinite loop, ie simple system halt */ \ + } \ + }) + + +#endif /* _SOS_ASSERT_H_ */ diff --git a/sos-code-article1/sos/errno.h b/sos-code-article1/sos/errno.h new file mode 100644 index 0000000..f13e740 --- /dev/null +++ b/sos-code-article1/sos/errno.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_ERRNO_H_ +#define _SOS_ERRNO_H_ + +/** + * @file errno.h + * + * SOS return value codes and errors. + */ + +/* Positive values of the error codes */ +#define SOS_OK 0 /* No error */ +#define SOS_EINVAL 1 /* Invalid argument */ +#define SOS_ENOSUP 2 /* Operation not supported */ +#define SOS_EFATAL 255 /* Internal fatal error */ + +/* A negative value means that an error occured. For + * example -SOS_EINVAL means that the error was "invalid + * argument" */ +typedef int sos_ret_t; + +#endif /* _SOS_ERRNO_H_ */ diff --git a/sos-code-article1/sos/klibc.c b/sos-code-article1/sos/klibc.c new file mode 100644 index 0000000..277a15c --- /dev/null +++ b/sos-code-article1/sos/klibc.c @@ -0,0 +1,271 @@ +/* Copyright (C) 2004 David Decotigny (with INSA Rennes for vsnprintf) + Copyright (C) 2003 The KOS Team + Copyright (C) 1999 Free Software Foundation + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "klibc.h" + +/* For an optimized version, see BSD sources ;) */ +void *memcpy(void *dst0, const void *src0, register unsigned int size) +{ + char *dst; + const char *src; + for (dst = (char*)dst0, src = (const char*)src0 ; + size > 0 ; + dst++, src++, size--) + *dst = *src; + return dst0; +} + +/* ditto */ +void *memset(void *dst0, register int c, register unsigned int length) +{ + char *dst; + for (dst = (char*) dst0 ; + length > 0 ; + dst++, length --) + *dst = (char)c; + return dst0; +} + +int memcmp(const void *s1, const void *s2, sos_size_t len) +{ + const unsigned char *c1, *c2; + unsigned int i; + + for (i = 0, c1 = s1, c2 = s2; i < len; i++, c1++, c2++) + { + if(*c1 != *c2) + return *c1 - *c2; + } + + return 0; +} + + +unsigned int strlen(register const char *str) +{ + unsigned int retval = 0; + + while (*str++) + retval++; + + return retval; +} + + +unsigned int strnlen(const char * s, sos_size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */continue; + + return sc - s; +} + + +char *strzcpy(register char *dst, register const char *src, register int len) +{ + int i; + + if (len <= 0) + return dst; + + for (i = 0; i < len; i++) + { + dst[i] = src[i]; + if(src[i] == '\0') + return dst; + } + + dst[len-1] = '\0'; + return dst; +} + + +char *strzcat (char *dest, const char *src, sos_size_t n) +{ + char *res = dest; + + for ( ; *dest ; dest++); + + for ( ; *src ; src++, dest++) { + *dest = *src; + n--; + if (n <= 0) + break; + } + + *dest = '\0'; + return res; +} + +int strcmp(register const char *s1, register const char *s2) +{ + while (*s1 == *s2++) + if (*s1++ == 0) + return (0); + + return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); +} + + +int strncmp(register const char *s1, register const char *s2, register int len) +{ + char c1 = '\0', c2 = '\0'; + + while (len > 0) + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + len--; + } + + return c1 - c2; +} + + +/* I (d2) borrowed and rewrote this for Nachos/INSA Rennes. Thanks to + them for having kindly allowed me to do so. */ +int vsnprintf(char *buff, sos_size_t len, const char * format, va_list ap) +{ + sos_size_t i, result; + + if (!buff || !format || (len < 0)) + return -1; + +#define PUTCHAR(thechar) \ + do { \ + if (result < len-1) \ + *buff++ = (thechar); \ + result++; \ + } while (0) + + result = 0; + for(i=0 ; format[i] != '\0' ; i++){ + switch (format[i]) + { + case '%': + i++; + switch(format[i]) + { + case '%': + { + PUTCHAR('%'); + break; + } + case 'i':; + case 'd': + { + int integer = va_arg(ap,int); + int cpt2 = 0; + char buff_int[16]; + + if (integer<0) + PUTCHAR('-'); + /* Ne fait pas integer = -integer ici parce que INT_MIN + n'a pas d'equivalent positif (int = [-2^31, 2^31-1]) */ + + do { + int m10 = integer%10; + m10 = (m10 < 0)? -m10:m10; + buff_int[cpt2++]=(char)('0'+ m10); + integer=integer/10; + } while(integer!=0); + + for(cpt2 = cpt2 - 1 ; cpt2 >= 0 ; cpt2--) + PUTCHAR(buff_int[cpt2]); + + break; + } + + case 'c': + { + int value = va_arg(ap,int); + PUTCHAR((char)value); + break; + } + + case 's': + { + char *string = va_arg(ap,char *); + if (! string) + string = "(null)"; + for( ; *string != '\0' ; string++) + PUTCHAR(*string); + break; + } + + case 'x': + { + unsigned int hexa = va_arg(ap,int); + unsigned int nb; + int i, had_nonzero = 0; + for(i=0 ; i < 8 ; i++) + { + nb = (unsigned int)(hexa << (i*4)); + nb = (nb >> 28) & 0xf; + // Skip the leading zeros + if (nb == 0) + { + if (had_nonzero) + PUTCHAR('0'); + } + else + { + had_nonzero = 1; + if (nb < 10) + PUTCHAR('0'+nb); + else + PUTCHAR('a'+(nb-10)); + } + } + if (! had_nonzero) + PUTCHAR('0'); + break; + } + break; + + default: + PUTCHAR('%'); + PUTCHAR(format[i]); + } + break; + + default: + PUTCHAR(format[i]); + } + } + + *buff = '\0'; + return result; +} + + +int snprintf(char * buff, sos_size_t len, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + len = vsnprintf(buff, len, format, ap); + va_end(ap); + + return len; +} diff --git a/sos-code-article1/sos/klibc.h b/sos-code-article1/sos/klibc.h new file mode 100644 index 0000000..a8b9d49 --- /dev/null +++ b/sos-code-article1/sos/klibc.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2003 The KOS Team + Copyright (C) 1999 Free Software Foundation + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_KLIBC_H_ +#define _SOS_KLIBC_H_ + +/** + * @file klibc.h + * + * Basic libc-style support for common useful functions (string.h, + * stdarg.h), some with slight non-standard behavior (see comments). + */ + +#include <sos/types.h> + +/* string.h functions */ + +void *memcpy(void *dst, const void *src, register unsigned int size ) ; +void *memset(void *dst, register int c, register unsigned int length ) ; +int memcmp(const void *s1, const void *s2, sos_size_t n); + +unsigned int strlen( register const char *str) ; +unsigned int strnlen(const char * s, sos_size_t maxlen); + +/** + * @note Same as strncpy(), with a slightly different semantic. + * Actually, strncpy(3C) says " The result will not be null-terminated + * if the length of 'from' is n or more.". Here, 'dst' is ALWAYS + * null-terminated. And its total len will ALWAYS be <= len, with + * null-terminating-char included. + */ +char *strzcpy( register char *dst, register const char *src, + register int len ) ; + +/** + * @note Same as strncat(), with the same semantic : 'dst' is ALWAYS + * null-terminated. And its total len will ALWAYS be <= len, with + * null-terminating-char included. + */ +char *strzcat (char *dest, const char *src, + const sos_size_t len); + +int strcmp(register const char *s1, register const char *s2 ); +int strncmp(register const char *s1, register const char *s2, + register int len ); + +/* Basic stdarg.h macros. Taken from gcc support files */ +#define __GNUC_VA_LIST +typedef void *__gnuc_va_list; +typedef __gnuc_va_list va_list; +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) +#define va_start(AP, LASTARG) \ + (AP = ((__gnuc_va_list) __builtin_next_arg (LASTARG))) +#define va_end(AP) \ + ((void)0) +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE)))) +#define __va_copy(dest, src) \ + (dest) = (src) + +/* stdarg.h functions. There might be a non-standard behavior: there + will always be a trailing '\0' in the resulting string */ +int vsnprintf(char *, sos_size_t, const char *, va_list); +int snprintf(char *, sos_size_t, const char *, /*args*/ ...) + __attribute__ ((format (printf, 3, 4))); + +#endif /* _SOS_KLIBC_H_ */ diff --git a/sos-code-article1/sos/main.c b/sos-code-article1/sos/main.c new file mode 100644 index 0000000..a5adb54 --- /dev/null +++ b/sos-code-article1/sos/main.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +/* Include definitions of the multiboot standard */ +#include <bootstrap/multiboot.h> +#include <sos/klibc.h> +#include <sos/assert.h> +#include <drivers/x86_videomem.h> +#include <drivers/bochs.h> + + + +/* The C entry point of our operating system */ +void sos_main(unsigned long magic, unsigned long addr) +{ + unsigned i; + + /* Grub sends us a structure, called multiboot_info_t with a lot of + precious informations about the system, see the multiboot + documentation for more information. */ + multiboot_info_t *mbi; + mbi = (multiboot_info_t *) addr; + + /* Setup bochs and console, and clear the console */ + sos_bochs_setup(); + + sos_x86_videomem_setup(); + sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE); + + /* Greetings from SOS */ + if (magic == MULTIBOOT_BOOTLOADER_MAGIC) + /* Loaded with Grub */ + sos_x86_videomem_printf(1, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)", + "SOS", ',', + (unsigned)(mbi->mem_upper >> 10) + 1, + (unsigned)mbi->mem_upper); + else + /* Not loaded with grub */ + sos_x86_videomem_printf(1, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Welcome to SOS"); + + sos_bochs_putstring("Message in a bochs\n"); + + + /* An operatig system never ends */ + for (;;) + continue; + + return; +} diff --git a/sos-code-article1/sos/types.h b/sos-code-article1/sos/types.h new file mode 100644 index 0000000..de54a9c --- /dev/null +++ b/sos-code-article1/sos/types.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_TYPES_H_ +#define _SOS_TYPES_H_ + +/** + * @file types.h + * + * SOS basic types definition + */ + +/** Memory size of an object (positive) */ +typedef unsigned int sos_size_t; + +/** Low-level sizes */ +typedef unsigned long int sos_ui32_t; /* 32b unsigned */ +typedef unsigned short int sos_ui16_t; /* 16b unsigned */ +typedef unsigned char sos_ui8_t; /* 8b unsigned */ + +typedef enum { FALSE=0, TRUE } sos_bool_t; + +/** Not a proper type, but highly useful with basic type + manipulations */ +#define NULL ((void*)0) + +#endif /* _SOS_TYPES_H_ */ diff --git a/sos-code-article1/support/build_image.sh b/sos-code-article1/support/build_image.sh new file mode 100755 index 0000000..43929cd --- /dev/null +++ b/sos-code-article1/support/build_image.sh @@ -0,0 +1,215 @@ +#!/bin/sh +# Copyright (C) 2003, David Decotigny + +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# 1) What does it do ? +# +# 1) Check where Grub is installed (lookup_grub) +# 2) Assign some local variables using the shell script arguments. +# a) Argument 1 : the destination (either a file or a drive, like a:) +# b) Argument 2 : the loader (i.e kernel) +# c) Argument 3 : options passed to the loader +# d) Argument 4 : the modules (that can be loaded optionally by Grub) +# 3) Test whether destination is a drive or a file +# 4) Create the directory structure inside the drive +# 5) Copy the loader in the drive +# 6) Generate the 'menu.txt' file used by Grub to generate the boot menu +# 7) Copy all modules +# 8) Copy the menu.txt file +# +# 2) Why is it so complex ? +# Because it must support various Grub/mtools installations and versions +# +# In fact, this shell script is used in the KOS (kos.enix.org) +# project. This operating system consists in a loader and many many +# modules that are linked together at boot time. It is much more +# complex that a simple monolithic kernel. +# +# For your simple monolithic kernel, you only need to give argument 1 +# and 2. + +print_usage () { + echo "Usage: $0 [X:|image] path/to/loader option path/to/modules..." + echo " where X: is a valid floppy drive on your computer" + echo " where image is any file name" + exit 1 +} + +grub_dirs_common="/usr/local/share/grub/i386-freebsd /usr/local/share/grub/i386-pc /usr/share/grub/i386-pc /usr/lib/grub/i386-pc /usr/local/grub /usr/share/grub/i386-redhat /usr/local/src/grub-0.5.94 $HOME/share/grub/i386-pc/" +sbin_grub_path="/usr/local/sbin /usr/sbin /sbin $HOME/sbin" + +PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin +export PATH + +MTOOLSRC=mtoolsrc +export MTOOLSRC + +# Redefined variables +FLOPPY_DRIVE=A: +IMG_FNAME=fd.img + +## +## Format disk image +## +init_image () { + echo "Initialize disk image $IMG_FILE..." + if [ ! -f $IMG_FNAME ] ; then + dd if=/dev/zero of=$IMG_FNAME bs=18k count=80 1>/dev/null 2>&1 + fi + + rm -f $MTOOLSRC + echo "drive u: file=\"$IMG_FNAME\" 1.44M filter" > $MTOOLSRC + + if mformat U: ; then : ; else + rm -f $MTOOLSRC + echo "drive u: file=\"$IMG_FNAME\" 1.44M" > $MTOOLSRC + if mformat U: ; then : ; else + rm -f $MTOOLSRC + echo "drive u: file=\"$IMG_FNAME\"" > $MTOOLSRC + mformat U: + fi + fi +} + + +## +## Format (real) floppy disk +## +init_floppy () { + echo "Formatting floppy..." + mformat $FLOPPY_DRIVE || exit 1 +} + + +lookup_grub () { + # Look for a correct GRUBDIR + for d in $grub_dirs_common ; do + if [ -d $d ] ; then + GRUBDIR=$d + break + fi + done + + # Try to guess with locate + if [ ! -d "$GRUBDIR" ] ; then + GRUBDIR=`locate stage2 | head -1 | xargs dirname 2>/dev/null` + fi + + # Look for a correct sbin/grub + for d in $sbin_grub_path ; do + if [ -x $d/grub ] ; then + SBIN_GRUB=$d/grub + break + fi + done + + if [ -d "$GRUBDIR" -a -x "$SBIN_GRUB" ] ; then + echo "Found correct grub installation in $GRUBDIR" + echo "Found correct /sbin/grub at $SBIN_GRUB" + else + echo "Couldn't find a correct grub installation." + exit 1 + fi +} + +## +## setup_disk [drive] +## => setup disk directory structure / copy files +## +setup_disk () { + echo "Setup destination disk..." + + mmd $1/boot + mmd $1/boot/grub + + if [ -d $GRUBDIR/stage1 ] ; then + mcopy $GRUBDIR/stage1/stage1 $1/boot/grub/ + mcopy $GRUBDIR/stage2/stage2 $1/boot/grub/ + else + mcopy $GRUBDIR/stage1 $1/boot/grub/ + mcopy $GRUBDIR/stage2 $1/boot/grub/ + fi + mmd $1/system + mmd $1/modules + + $SBIN_GRUB --batch <<EOT 1>/dev/null 2>/dev/null || exit 1 +device (fd0) $IMG_FNAME +install (fd0)/boot/grub/stage1 (fd0) (fd0)/boot/grub/stage2 p (fd0)/boot/grub/menu.txt +quit +EOT +} + + + +################################################# +## Real start +## +#[ "$#" -lt 3 ] && print_usage + +lookup_grub + +dest="$1" ; shift +loader_fname="$1" ; shift +options="$1" ; shift +modules="$*" + +# Init destination disk +case x$dest in + x*:) + drive=$dest + IMG_FNAME=$dest + FLOPPY_DRIVE=$dest + init_floppy + ;; + x*) + drive=U: + IMG_FNAME=$dest + init_image + ;; +esac + +# Create directory structure +setup_disk $drive + +# Copy the loader +mcopy -bo $loader_fname $drive/system/`basename $loader_fname` + +# Generate the menu.txt file +rm -f menu.txt +cat <<EOF > menu.txt +timeout 0 +default 0 +title Simple OS +root (fd0) +kernel /system/`basename $loader_fname` $options +EOF + +# Copy the modules +for f in $modules ; do + if [ ! -f $f ] ; then + echo "ERROR: module $f not correctly compiled in." + exit 1 + fi + if ! mcopy -bo $f $drive/modules/`basename $f` ; then + echo "ERROR: module $f could not be transferred to floppy." + exit 1 + fi + echo module /modules/`basename $f` >> menu.txt +done + +# Transfers the menu.txt file to floppy +mcopy -bo menu.txt $drive/boot/grub/ diff --git a/sos-code-article1/support/sos.lds b/sos-code-article1/support/sos.lds new file mode 100644 index 0000000..4d87061 --- /dev/null +++ b/sos-code-article1/support/sos.lds @@ -0,0 +1,107 @@ +/* Copyright (C) 2003, Thomas Petazzoni + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +/* We generate binary in the ELF format */ +OUTPUT_FORMAT("elf32-i386","elf32-i386","elf32-i386"); + +/* The entry point is _start (defined in boot.S) */ +ENTRY(_start) + +/* The architecture is i386 */ +OUTPUT_ARCH("i386") + +SECTIONS +{ + /* our kernel is loaded at 0x200000 */ + . = 0x200000; + __b_load = .; + + /* the multiboot header MUST come early enough in the output + object file */ + .multiboot : + { + /* The multiboot section (containing the multiboot header) + goes here */ + *(.multiboot); + + /* + * With the following line, we force this section to be + * allocated in the output file as soon as possible, no matter + * when the file containing the multiboot header (multiboot.S) + * is compiled. This is to conform to the multiboot spec, which + * says "The Multiboot header must be contained completely + * within the first 8192 bytes of the OS image, and must be + * longword (32-bit) aligned." + */ + LONG(0); + } + + /* Defines a symbol '__b_kernel to mark the start of the kernel + code/data */ + . = ALIGN(4096); + __b_kernel = .; + + /* Beginning of the text section */ + .text ALIGN(4096) : + { + /* This section includes the code */ + *(.text*) + /* Defines the 'etext' and '_etext' at the end */ + PROVIDE(etext = .); + PROVIDE(_etext = .); + } + + /* Beginning of the data section */ + .data . : + { *(.data*) + PROVIDE(edata = .); + PROVIDE(_edata = .); + } + + /* Beginning of the read-only data section */ + .rodata . : + { *(.rodata*) + PROVIDE(erodata = .); + PROVIDE(_erodata = .); + } + /* We take note of the end of the data to load */ + __e_load = .; + + /* Beginning of the BSS section (global uninitialized data) */ + .bss SIZEOF(.rodata) + ADDR(.rodata) : + { *(.bss) + *(COMMON) + PROVIDE(ebss = .); + PROVIDE(_ebss = .); + } + + /* We take note of the end of the kernel */ + __e_kernel = .; + + /* We don't care of the note, indent, comment, etc.. sections + generated by gcc */ + /DISCARD/ :{ + *(.note*) + *(.indent) + *(.comment) + *(.stab) + *(.stabstr) + } + +} + diff --git a/sos-code-article2/INSTALL b/sos-code-article2/INSTALL new file mode 100644 index 0000000..7c7d619 --- /dev/null +++ b/sos-code-article2/INSTALL @@ -0,0 +1,118 @@ + + SOS: A Simple Operating System + + Compilation/Installation/Test instructions + + +Compilation +=========== + +IMPORTANT +--------- + +Don't forget to run 'make clean' before 'make' after you have modified +any source or header file(s). + + +On a x86 host where grub is correctly installed +----------------------------------------------- + +Simply run 'make' + + +On a non-x86 host (without grub of course !) +-------------------------------------------- + +See extra/README + + +On an x86 host without Grub, or with a buggy Grub +------------------------------------------------- + +See extra/README + +How do I know I have a buggy grub installation ? Answer: in the qemu +PC emulator, Grub hangs while loading the kernel + + +Installation +============ + +Nothing special to do besides compiling + + +Test the SOS Kernel +=================== + +On a x86 real machine with Grub installed +----------------------------------------- + + 1st method + => Boot the sos.elf file (append 'kernel=<path_to>sos.elf' in the + menu.lst or type it on Grub's command line) from a hard disk, a + floppy, or from the network + + 2nd method + => Copy the file 'fd.img' to a floppy and boot from it + + +On a x86 real machine without Grub installed +-------------------------------------------- + + 1st method + => see extra/README to compile with the grub floppy image we provide, + copy the file 'fd.img' to a floppy, and boot from it + + 2nd method + => see extra/README to compile with the boot sector we provide (up to + article 2 only), copy the file 'extra/sos_bsect.img' to a floppy, + and boot from it + + +Inside a PC emulator (x86 and non-x86 hosts) +-------------------------------------------- + +Tested on both the bochs emulator (x86/linux, sparc/solaris and +ppc/linux hosts, 'apt-get install bochs-x vgabios' on debian +testing/unstable), and the qemu system emulator (with libsdl +installed: 'apt-get install libsdl1.2-dev' on debian +testing/unstable). + + 1/ Grub is installed on the host (x86 hosts only) + - - - - - - - - - - - - - - - - - - - - - - - - - + + bochs: boot from the file 'fd.img'. Example of a ~/.bochsrc: + floppya: 1_44=/home/d2/sos/fd.img, status=inserted + romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000 + vgaromimage: /usr/share/vgabios/vgabios.bin + megs:63 # 63 Mo de RAM + + qemu: run 'qemu -fda fd.img' + If grub hangs while loading the kernel, please go to method 2/ + + 2/ Grub is not installed (all hosts) + - - - - - - - - - - - - - - - - - - + + See extra/README to generate a floppy image with the Grub floppy + image we provide, and: + + bochs: boot from the file 'fd.img' + + qemu: run 'qemu -fda fd.img' + + 3/ Bonus: boot with the bootsector we provide (all hosts, up to art. 2 ONLY !) + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + See extra/README to generate a floppy image with the boot sector we + provide, and: + + bochs: boot from the file 'extra/sos_bsect.img' + + qemu: run 'qemu -fda extra/sos_qemu.img' + + NOTE: After article 2, this way of booting is not supported: please + use the method 2/ above. + + +-- +David Decotigny diff --git a/sos-code-article2/LICENSE b/sos-code-article2/LICENSE new file mode 100644 index 0000000..60549be --- /dev/null +++ b/sos-code-article2/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) 19yy 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. + + <signature of Ty Coon>, 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/sos-code-article2/Makefile b/sos-code-article2/Makefile new file mode 100644 index 0000000..fd1fa89 --- /dev/null +++ b/sos-code-article2/Makefile @@ -0,0 +1,56 @@ +CC=i586-elf-gcc +LD=i586-elf-ld +CFLAGS = -Wall -nostdlib -nostdinc -ffreestanding -DKERNEL_SOS +LDFLAGS = --warn-common +OBJECTS = bootstrap/multiboot.o \ + hwcore/idt.o hwcore/gdt.o \ + hwcore/exception.o hwcore/exception_wrappers.o \ + hwcore/irq.o hwcore/irq_wrappers.o hwcore/i8259.o \ + hwcore/i8254.o drivers/x86_videomem.o drivers/bochs.o \ + sos/klibc.o sos/main.o + +KERNEL_OBJ = sos.elf +MULTIBOOT_IMAGE = cdrom.iso +PWD := $(shell pwd) + +# Main target +all: $(MULTIBOOT_IMAGE) + +$(MULTIBOOT_IMAGE): $(KERNEL_OBJ) + # ./support/build_image.sh $@ $< + if [ ! -e cdrom/boot/grub/stage2_eltorito ]; then \ + mkdir -p cdrom/boot/grub; \ + echo "Please copy grub's stage2_eltorito to cdrom/boot/grub."; \ + exit -1; \ + fi + cp $(KERNEL_OBJ) cdrom + echo timeout 0 > cdrom/boot/grub/menu.lst + echo title Simple OS >> cdrom/boot/grub/menu.lst + echo kernel /$(KERNEL_OBJ) >> cdrom/boot/grub/menu.lst + genisoimage -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 \ + -boot-info-table -input-charset ascii -A SOS -o $(MULTIBOOT_IMAGE) cdrom + +$(KERNEL_OBJ): $(OBJECTS) ./support/sos.lds + $(LD) $(LDFLAGS) -T ./support/sos.lds -o $@ $(OBJECTS) + -nm -C $@ | cut -d ' ' -f 1,3 > sos.map + +-include .mkvars + +# Create objects from C source code +%.o: %.c + $(CC) -I$(PWD) -c $< $(CFLAGS) -o $@ + +# Create objects from assembler (.S) source code +%.o: %.S + $(CC) -I$(PWD) -c $< $(CFLAGS) -DASM_SOURCE=1 -o $@ + +# Clean directory +clean: + $(RM) *.img *.iso *.o mtoolsrc *~ menu.txt *.img *.elf *.bin *.map + $(RM) *.log *.out bochs* + $(RM) bootstrap/*.o bootstrap/*~ + $(RM) drivers/*.o drivers/*~ + $(RM) hwcore/*.o hwcore/*~ + $(RM) sos/*.o sos/*~ + $(RM) support/*~ + $(RM) extra/*~ diff --git a/sos-code-article2/README b/sos-code-article2/README new file mode 100644 index 0000000..efbbc89 --- /dev/null +++ b/sos-code-article2/README @@ -0,0 +1,90 @@ + + SOS: A Simple Operating System + + +This is SOS, a Simple Operating System for i386-family +processors. This is as simple as possible to show a way to program a +basic Operating System on real common hardware (PC). The code should +be easily readable and understandable thanks to frequent comments, and +references to external documentation. We chose to implement the basic +features of an OS, thus making design decisions targetting towards +simplicity of understanding, covering most of the OS classical +concepts, but not aiming at proposing yet another full-fledged +competitive OS (Linux is quite good at it). However, for those who +would like to propose some enhancements, we are open to any code +suggestions (patches only, please). And yes, there might be bugs in +the code, so please send us any bug report, and/or patches ! + +The OS comes as a set of articles (in french) to be published in the +journal "Linux Magazine France". Each month, the part of the code +related to the current article's theme is released (see VERSION file), +and the resulting OS can be successfully compiled and run, by booting +it from a floppy on a real machine (tested AMD k7, Cyrix and Intel P4 +pentiums), or through an x86 emulator (bochs or qemu). The resulting +OS is available as a multiboot compliant ELF kernel (sos.elf) and as a +floppy image (fd.img). It provides a very very very basic demo whose +aim is to understand how everything works, not to animate sprites on +the screen with 5:1 dolby sound. + +The initial technical features and lack-of-features of the OS are: + - monolithic kernel, fully interruptible, non-preemptible (big kernel + lock), target machines = i386 PC or better + - compiles on any host where the gcc/binutils toolchain (target + i586-gnu) is available. Can be tested on real i486/pentium + hardware, or on any host that can run an i486/pentium PC emulator + (bochs or qemu) + - kernel loaded by grub, or by a sample bootsector (up to article 2 + ONLY) + - clear separation of physical memory and virtual memory concepts, + even inside the kernel: no identity-mapping of the physical memory + inside the kernel (allows to move virtual mappings of kernel pages + at run-time, eg to free ISA DMA pages, and to avercome the 4G RAM + barrier) + - slab-type kernel memory allocation + - no swap, no reverse mapping + - VERY simple drivers: keyboard, x86 video memory, IDE disks + - logical devices: partitions, FAT filesystem, "hard-coded" + mountpoints only (~ MSDOS) + - no network stack + - user-level features: ELF loader (no shared libraries), processes, + user threads (kernel-level scheduling only), mmap API, basic VFS + +To understand where to look at for what, here is a brief description: + - Makefile: the (ONLY) makefile of the OS. Targets are basically + 'all' and 'clean' + - bootstrap/ directory: code to load the kernel. Both the stuff + needed for a multiboot-compliant loader (eg grub) AND a bootsector + are provided. The bootsector may only be used up to article 2. + - sos/ directory: the entry routine for the kernel (main.c), various + systemwide header files, a set of common useful C routines + ("nano-klibc"), and kernel subsystems (kernel memory management, + etc...) + - hwcore/ directory: Low-level CPU- and kernel-related routines + (interrupt/exception management, translation tables and segment + registers, ...) + - drivers/ directory: basic kernel drivers for various (non CPU) + devices (keyboard, x86 video memory, bochs 0xe9 port, ...). Used + mainly for debugging + - support/ directory: scripts and configuration files to build the + floppy images + - extra/ directory: a set of configuration files to be customized for + non-x86 host installations (yes, we primarily develop SOS on a ppc, for + the x86 target of course), or for grub-less installations. See + README file in this directory. + +The code is licensed under the terms of the GNU GPL version 2 (see +LICENSE file). + +Enjoy ! + + David Decotigny, Thomas Petazzoni, the Kos team + http://sos.enix.org/ + http://david.decotigny.free.fr/ + http://kos.enix.org/~thomas/ + http://kos.enix.org/ + + +-- +David Decotigny + +PS: Made with a Mac. diff --git a/sos-code-article2/VERSION b/sos-code-article2/VERSION new file mode 100644 index 0000000..be4a929 --- /dev/null +++ b/sos-code-article2/VERSION @@ -0,0 +1,11 @@ +SOS -- Simple OS +Copyright (C) 2003,2004 The SOS Team (David Decotigny & Thomas Petazzoni) + +Version "Article 2" -- Basic interrupt & processor exception management + + 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. + + See the LICENSE file included in the distribution. diff --git a/sos-code-article2/bootstrap/multiboot.S b/sos-code-article2/bootstrap/multiboot.S new file mode 100644 index 0000000..4a7c65b --- /dev/null +++ b/sos-code-article2/bootstrap/multiboot.S @@ -0,0 +1,74 @@ +/* Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + + +/* The operating system is booted by Grub, so we almost have nothing + to do to boot it. We only have to conform to the Multiboot + standard, as defined by the Grub documentation */ + +#define ASM 1 +/* The multiboot.h header contains a lot of multiboot standard + definitions */ +#include "multiboot.h" + + /* The multiboot header itself. It must come first. */ +.section ".multiboot" + /* Multiboot header must be aligned on a 4-byte boundary */ + .align 4 +multiboot_header: + /* magic= */ .long MULTIBOOT_HEADER_MAGIC + /* flags= */ .long MULTIBOOT_HEADER_FLAGS + /* checksum= */ .long -(MULTIBOOT_HEADER_MAGIC \ + +MULTIBOOT_HEADER_FLAGS) + /* header_addr= */ .long multiboot_header + /* load_addr= */ .long __b_kernel + /* load_end_addr=*/ .long __e_load + /* bss_end_addr= */ .long __e_kernel + /* entry_addr= */ .long multiboot_entry + +/* Here is the beginning of the code of our operating system */ +.text + +.globl start, _start +start: +_start: +multiboot_entry: + /* Set up a stack */ + movl $(stack + MULTIBOOT_STACK_SIZE), %ebp + movl %ebp, %esp + + /* Set EFLAGS to 0 */ + pushl $0 + /* pop stack into the EFLAGS register */ + popf + + /* Push the magic and the address on the stack, so that they + will be the parameters of the cmain function */ + pushl %ebx + pushl %eax + + /* Call the cmain function (os.c) */ + call EXT_C(sos_main) + + /* Should never get there */ +loop: + hlt + jmp loop + + /* Here is the stack */ +.comm stack, MULTIBOOT_STACK_SIZE diff --git a/sos-code-article2/bootstrap/multiboot.h b/sos-code-article2/bootstrap/multiboot.h new file mode 100644 index 0000000..bee676d --- /dev/null +++ b/sos-code-article2/bootstrap/multiboot.h @@ -0,0 +1,129 @@ +#ifndef __MULTIBOOT_H__ +#define __MULTIBOOT_H__ + +/* multiboot.h - the header for Multiboot */ +/* Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Macros. */ + +/* The magic number for the Multiboot header. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* The flags for the Multiboot header. */ +#define MULTIBOOT_HEADER_FLAGS 0x00010003 + +/* The magic number passed by a Multiboot-compliant boot loader. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* The size of our stack (16KB). */ +#define MULTIBOOT_STACK_SIZE 0x4000 + +#define MULTIBOOT_CMDLINE 4 +#define MULTIBOOT_MODS 8 + +/* C symbol format. HAVE_ASM_USCORE is defined by configure. */ +#ifdef HAVE_ASM_USCORE +# define EXT_C(sym) _ ## sym +#else +# define EXT_C(sym) sym +#endif + +#ifndef ASM +/* Do not include here in boot.S. */ + + + +/* Types. */ + +/* The Multiboot header. */ +typedef struct multiboot_header +{ + unsigned long magic; + unsigned long flags; + unsigned long checksum; + unsigned long header_addr; + unsigned long load_addr; + unsigned long load_end_addr; + unsigned long bss_end_addr; + unsigned long entry_addr; +} multiboot_header_t; + +/* The symbol table for a.out. */ +typedef struct aout_symbol_table +{ + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long reserved; +} aout_symbol_table_t; + +/* The section header table for ELF. */ +typedef struct elf_section_header_table +{ + unsigned long num; + unsigned long size; + unsigned long addr; + unsigned long shndx; +} elf_section_header_table_t; + +/* The Multiboot information. */ +typedef struct multiboot_info +{ + unsigned long flags; + unsigned long mem_lower; + unsigned long mem_upper; + unsigned long boot_device; + unsigned long cmdline; + unsigned long mods_count; + unsigned long mods_addr; + union + { + aout_symbol_table_t aout_sym; + elf_section_header_table_t elf_sec; + } u; + unsigned long mmap_length; + unsigned long mmap_addr; + unsigned long drives_length; + unsigned long drives_addr; +} multiboot_info_t; + +/* The module structure. */ +typedef struct module +{ + unsigned long mod_start; + unsigned long mod_end; + unsigned long string; + unsigned long reserved; +} module_t; + +/* The memory map. Be careful that the offset 0 is base_addr_low + but no size. */ +typedef struct memory_map +{ + unsigned long size; + unsigned long base_addr_low; + unsigned long base_addr_high; + unsigned long length_low; + unsigned long length_high; + unsigned long type; +} memory_map_t; + +void dump_multiboot_info(multiboot_info_t *mbi); + +#endif /* ! ASM */ + +#endif /* __MULTIBOOT_H__ */ diff --git a/sos-code-article2/cdrom/boot/grub/menu.lst b/sos-code-article2/cdrom/boot/grub/menu.lst new file mode 100644 index 0000000..351100d --- /dev/null +++ b/sos-code-article2/cdrom/boot/grub/menu.lst @@ -0,0 +1,3 @@ +timeout 0 +title Simple OS +kernel /sos.elf diff --git a/sos-code-article2/cdrom/boot/grub/stage2_eltorito b/sos-code-article2/cdrom/boot/grub/stage2_eltorito Binary files differnew file mode 100644 index 0000000..6d82f08 --- /dev/null +++ b/sos-code-article2/cdrom/boot/grub/stage2_eltorito diff --git a/sos-code-article2/cdrom/sos.elf b/sos-code-article2/cdrom/sos.elf Binary files differnew file mode 100755 index 0000000..0898db5 --- /dev/null +++ b/sos-code-article2/cdrom/sos.elf diff --git a/sos-code-article2/drivers/bochs.c b/sos-code-article2/drivers/bochs.c new file mode 100644 index 0000000..db18599 --- /dev/null +++ b/sos-code-article2/drivers/bochs.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <hwcore/ioports.h> +#include <sos/klibc.h> + +#include "bochs.h" + +/* This is a special hack that is only useful when running the + operating system under the Bochs emulator. */ +#define SOS_BOCHS_IOPORT 0xe9 + +sos_ret_t sos_bochs_setup(void) +{ + return SOS_OK; +} + + +#define sos_bochs_putchar(chr) \ + outb((chr), SOS_BOCHS_IOPORT) + +sos_ret_t sos_bochs_putstring(const char* str) +{ + for ( ; str && (*str != '\0') ; str++) + sos_bochs_putchar(*str); + + return SOS_OK; +} + + +sos_ret_t sos_bochs_puthex(unsigned val, int nbytes) +{ + unsigned c; + +#define BOCHS_PRTHEX(q) \ + ({ unsigned char r; if ((q) >= 10) r='a'+(q)-10; \ + else r='0'+(q); sos_bochs_putchar(r); }) + + switch (nbytes) + { + case 4: + c = (val >> 24) & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + case 3: + c = (val >> 16) & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + case 2: + c = (val >> 8) & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + case 1: + c = val & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + } + + return SOS_OK; +} + + +sos_ret_t sos_bochs_hexdump(const void* addr, int nbytes) +{ + int offs; + for (offs = 0 ; offs < nbytes ; offs++) + { + const unsigned char *c; + + if ((offs % 16) == 0) + { + sos_bochs_putstring("0x"); + sos_bochs_puthex(offs, 4); + } + + if ((offs % 8) == 0) + sos_bochs_putstring(" "); + + c = (const unsigned char*)(addr + offs); + sos_bochs_puthex(*c, 1); + sos_bochs_putstring(" "); + + if (((offs + 1) % 16) == 0) + sos_bochs_putstring("\n"); + } + + if (offs % 16) + sos_bochs_putstring("\n"); + + return SOS_OK; +} + + +sos_ret_t sos_bochs_printf(const char *format, /* args */...) +{ + char buff[256]; + va_list ap; + + va_start(ap, format); + vsnprintf(buff, sizeof(buff), format, ap); + va_end(ap); + + return sos_bochs_putstring(buff); +} diff --git a/sos-code-article2/drivers/bochs.h b/sos-code-article2/drivers/bochs.h new file mode 100644 index 0000000..310b023 --- /dev/null +++ b/sos-code-article2/drivers/bochs.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_BOCHS_H_ +#define _SOS_BOCHS_H_ + +/** + * @file bochs.h + * + * If you compiled Bochs with the --enable-e9-hack, then any character + * printed to the 0xE9 I/O port is printed to the xterm that is + * running Bochs. This may appear to be a detail, but in fact, this + * functionnality is *VERY* precious for debugging purposes. This + * """driver""" handles this feature. + */ + +#include <sos/errno.h> +#include <sos/types.h> + +sos_ret_t sos_bochs_setup(void); + +sos_ret_t sos_bochs_putstring(const char* str); + +/** Print the least signficant 32 (nbytes == 4), 24 (nbytes == 3), 16 + (nbytes == 2) or 8 (nbytes == 1) bits of val in hexadecimal. */ +sos_ret_t sos_bochs_puthex(unsigned val, int nbytes); + +/** hexdump-style pretty printing */ +sos_ret_t sos_bochs_hexdump(const void* addr, int nbytes); + +/** + * Print the formatted string. Very restricted version of printf(3): + * 1/ can print max 255 chars, 2/ supports only %d/%i, %c, %s, %x + * without any support for flag charachters (eg %08x). + */ +sos_ret_t sos_bochs_printf(const char *format, /* args */...) + __attribute__ ((format (printf, 1, 2))); + +#endif diff --git a/sos-code-article2/drivers/x86_videomem.c b/sos-code-article2/drivers/x86_videomem.c new file mode 100644 index 0000000..cc4b79c --- /dev/null +++ b/sos-code-article2/drivers/x86_videomem.c @@ -0,0 +1,128 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <sos/klibc.h> +#include <hwcore/ioports.h> + +#include "x86_videomem.h" + +/* The text video memory starts at address 0xB8000. Odd bytes are the + ASCII value of the character, even bytes are attribute for the + preceding character. */ +#define VIDEO 0xb8000 + + +/* Console screen size */ +#define LINES 25 +#define COLUMNS 80 + + +/** The structure of a character element in the video memory. @see + http://webster.cs.ucr.edu/AoA DOS edition chapter 23 */ +typedef struct { + unsigned char character; + unsigned char attribute; +} __attribute__ ((packed)) x86_video_mem[LINES*COLUMNS]; + + + +/** The base pointer for the video memory */ +static volatile x86_video_mem *video = (volatile x86_video_mem*)VIDEO; + +sos_ret_t sos_x86_videomem_setup(void) +{ + /* + * Hide cursor. @see Ralf Brown's interrupt (and port) list + * http://www-2.cs.cmu.edu/~ralf/files.html + */ +#define CRT_REG_INDEX 0x3d4 +#define CRT_REG_DATA 0x3d5 + + /* CRT index port => ask for access to register 0xa ("cursor + start") */ + outb(0x0a, CRT_REG_INDEX); + + /* (RBIL Tables 708 & 654) CRT Register 0xa => bit 5 = cursor OFF */ + outb(1 << 5, CRT_REG_DATA); + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_cls(unsigned char attribute) +{ + /* Clears the screen */ + int i; + for(i = 0 ; i < LINES*COLUMNS ; i++) + { + (*video)[i].character = 0; + (*video)[i].attribute = attribute; + } + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_putstring(unsigned char row, unsigned char col, + unsigned char attribute, + const char *str) +{ + unsigned video_offs = row*COLUMNS + col; + + if (video_offs >= LINES*COLUMNS) + return -SOS_EINVAL; + + for ( ; str && *str && (video_offs < LINES*COLUMNS) ; str++, video_offs++) + { + (*video)[video_offs].character = (unsigned char)*str; + (*video)[video_offs].attribute = attribute; + } + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_putchar(unsigned char row, unsigned char col, + unsigned char attribute, + unsigned char c) +{ + unsigned video_offs = row*COLUMNS + col; + + if (video_offs >= LINES*COLUMNS) + return -SOS_EINVAL; + + (*video)[video_offs].character = c; + (*video)[video_offs].attribute = attribute; + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_printf(unsigned char row, unsigned char col, + unsigned char attribute, + const char *format, /* args */...) +{ + char buff[256]; + va_list ap; + + va_start(ap, format); + vsnprintf(buff, sizeof(buff), format, ap); + va_end(ap); + + return sos_x86_videomem_putstring(row, col, attribute, buff); +} diff --git a/sos-code-article2/drivers/x86_videomem.h b/sos-code-article2/drivers/x86_videomem.h new file mode 100644 index 0000000..31a9dfc --- /dev/null +++ b/sos-code-article2/drivers/x86_videomem.h @@ -0,0 +1,98 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_X86_VIDEOMEM_H_ +#define _SOS_X86_VIDEOMEM_H_ + +/** + * @file x86_videomem.h + * + * On x86 PC platforms, the text mode screen memory (and CGA/EGA/VGA + * too) is mapped into physical memory. This file handles access to + * this screen, supposed to be set in text-mode, through this memory + * area. All the functions below print the characters directly to the + * memory, without interpreting the escaped characters (such as \n, + * \r...) + */ + +#include <sos/errno.h> + +/** + * x86 video attributes + * See http://webster.cs.ucr.edu/AoA/DOS/ch23/CH23-1.html + */ +/* Normal and Dark/Light foreground */ +#define SOS_X86_VIDEO_FG_BLACK 0 +#define SOS_X86_VIDEO_FG_DKGRAY 8 +#define SOS_X86_VIDEO_FG_BLUE 1 +#define SOS_X86_VIDEO_FG_LTBLUE 9 +#define SOS_X86_VIDEO_FG_GREEN 2 +#define SOS_X86_VIDEO_FG_LTGREEN 10 +#define SOS_X86_VIDEO_FG_CYAN 3 +#define SOS_X86_VIDEO_FG_LTCYAN 11 +#define SOS_X86_VIDEO_FG_RED 4 +#define SOS_X86_VIDEO_FG_LTRED 12 +#define SOS_X86_VIDEO_FG_MAGENTA 5 +#define SOS_X86_VIDEO_FG_LTMAGENTA 13 +#define SOS_X86_VIDEO_FG_BROWN 6 +#define SOS_X86_VIDEO_FG_YELLOW 14 +#define SOS_X86_VIDEO_FG_LTGRAY 7 +#define SOS_X86_VIDEO_FG_WHITE 15 +/* Background */ +#define SOS_X86_VIDEO_BG_BLACK (0 << 4) +#define SOS_X86_VIDEO_BG_BLUE (1 << 4) +#define SOS_X86_VIDEO_BG_GREEN (2 << 4) +#define SOS_X86_VIDEO_BG_CYAN (3 << 4) +#define SOS_X86_VIDEO_BG_RED (4 << 4) +#define SOS_X86_VIDEO_BG_MAGENTA (5 << 4) +#define SOS_X86_VIDEO_BG_BROWN (6 << 4) +#define SOS_X86_VIDEO_BG_LTGRAY (7 << 4) +/* Blinking */ +#define SOS_X86_VIDEO_FG_BLINKING (1 << 7) + + +/** Setup the video RAM mapping and clear the screen */ +sos_ret_t sos_x86_videomem_setup(void); + +/** Clears the screen and set the background color as given by + attribute */ +sos_ret_t sos_x86_videomem_cls(unsigned char attribute); + +/** Print the string on the scren with the given attribute. Does not + handle scrolling */ +sos_ret_t sos_x86_videomem_putstring(unsigned char row, unsigned char col, + unsigned char attribute, + const char *str); + +/** Print the character on the scren with the given attribute. Does not + handle scrolling */ +sos_ret_t sos_x86_videomem_putchar(unsigned char row, unsigned char col, + unsigned char attribute, + unsigned char c); + +/** + * Print the formatted string. Very restricted version of printf(3): + * 1/ can print max 255 chars, 2/ supports only %d/%i, %c, %s, %x + * without any support for flag charachters (eg %08x). + */ +sos_ret_t sos_x86_videomem_printf(unsigned char row, unsigned char col, + unsigned char attribute, + const char *format, /* args */...) + __attribute__ ((format (printf, 4, 5))); + +#endif /* _SOS_X86_VIDEOMEM_H_ */ diff --git a/sos-code-article2/extra/Makefile b/sos-code-article2/extra/Makefile new file mode 100644 index 0000000..f858aa6 --- /dev/null +++ b/sos-code-article2/extra/Makefile @@ -0,0 +1,40 @@ +OBJCOPY=objcopy + +all: sos_qemu.img + +-include ../.mkvars + +# The image is the simple concatenation of the boot sector and the kernel +# It may be use in bochs or on a real floppy, but NOT in qemu (see below) +sos_bsect.img: bsect.bin sos.bin + cat $^ > $@ + @echo "[31mYou can use the $@ image in bochs or on a real floppy (NOT qemu)[m" + +# For qemu, the trick is to tell it we have *more* than 1440 sectors (720kB). +# Rtherwise the qemu disk geometry will be configured to be that of a 720kB +# floppy, while our boot sector assumes it to be 1.44MB +sos_qemu.img: sos_bsect.img + # Padding with 0s after the bsect/kernel image + cat $< /dev/zero | dd of=$@ bs=1k count=1440 + @echo "[31mYou can use the $@ image in qemu, bochs, or on a real floppy[m" + +# we extract the boot sector from the main ELF binary +bsect.bin: sos_bsect.elf + $(OBJCOPY) -v -O binary -j .bootsect $< $@ + +# we extract the kernel code from the main ELF binary +sos.bin: sos_bsect.elf + $(OBJCOPY) -v -O binary -R .bootsect $< $@ + +# The main ELF binary contains the boot sector and the kernel code +# linked together (hence we deal with a SINGLE image that we split +# above) because they share some symbol definitions +sos_bsect.elf: bootsect.o compile_kernel + $(LD) --warn-common -T ./sos_bsect.lds -o $@ \ + bootsect.o $(wildcard ../hwcore/*.o ../drivers/*.o ../sos/*.o) + +compile_kernel: + $(MAKE) -C .. + +clean: + $(RM) *.img *.elf *.bin *~ *.o *.out diff --git a/sos-code-article2/extra/README b/sos-code-article2/extra/README new file mode 100644 index 0000000..0272f1f --- /dev/null +++ b/sos-code-article2/extra/README @@ -0,0 +1,73 @@ + +Contents of the extra/ directory +================================ + +Data and configuration files to support generation of sos on non-x86 +and/or grub-less hosts: + - dot.mkvars: file to copy as .mkvars in the root directory to + compile on a non-x86 host, and to generate the grub floppy image on + a grub-less host + - grub.img.gz: compressed image of a Grub floppy (without any + kernel). Used by dot.mkvars. + - mtoolsrc: file needed by .mkvars to compile a the floppy image + +Support of a sos-specific boot sector: + - Makefile: rules to compile sos_bsect.img, the floppy image with the + boot sector and the Sos + - bootsect.S: x86 Sos boot sector (GNU as). Depends on sos_bsect.lds + - sos_bsect.lds: ld script to bind the boot sector with the remaining + of the kernel + +Misc: + - qemu-port-e9.diff: patch over qemu to support the bochs "port 0xe9 hack" + + +What you can do with these files +================================ + + +*** Compile SOS from another architecture: +------------------------------------------ + - compile a cross-compiler for the i586-gnu target. This involves + compiling the binutils and gcc. Here are example configuration + options for them: + binutils (replace sparc-cun-solaris with your arch): + ../binutils-2.13/configure --prefix=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/stow/binutils-2.11 --host=sparc-sun-solaris2.7 i586-gnu + make && make install + gcc (ditto): + CFLAGS="-O2 -Dinhibit_libc" ../gcc-3.2/configure --target=i586-gnu --prefix=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/stow/gcc-3.2 --with-as=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/bin/as --with-ld=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/bin/ld --with-gnu-as --with-gnu-ld --enable-languages=c --disable-shared --disable-multilib --disable-nls --enable-threads=single + make && make install + - compile the mtools + - copy dot.mkvars to the root directory of SOS, as ".mkvars" + - customize the CC/LD/... variables to suit your cross-compiler + installatioon + - now you may run make from the SOS root directory, it should + generate the Grub boot floppy image. The following warning is + normal: + .mkvars:16: attention : écrasement des commandes pour la cible « grub-sos.img » + Makefile:92: attention : anciennes commandes ignorées pour la cible « grub-sos.img » + + +*** To compile SOS from an x86 where grub is not or incorrectly installed: +-------------------------------------------------------------------------- + - copy dot.mkvars to the root directory of SOS, as ".mkvars" + - customize the CC/LD/... variables to suit your cross-compiler + installatioon + - now you may run make from the SOS root directory, it should + generate the Grub boot floppy image. The following warning is + normal: + .mkvars:16: attention : écrasement des commandes pour la cible « grub-sos.img » + Makefile:92: attention : anciennes commandes ignorées pour la cible « grub-sos.img » + + +*** To compile SOS with its own bootloader: +------------------------------------------- + - for cross-architecture compilation: see above + - cd to this extra/ directory + - run 'make' + - the floppy image is: sos_bsect.img + NOTE : SOS will not boot correctly this way after article 2 ! + + +-- +David Decotigny diff --git a/sos-code-article2/extra/bootsect.S b/sos-code-article2/extra/bootsect.S new file mode 100644 index 0000000..f01ca20 --- /dev/null +++ b/sos-code-article2/extra/bootsect.S @@ -0,0 +1,393 @@ + +/* + * @(#) $Id: bootsect.S,v 1.6 2004/06/18 07:43:51 d2 Exp $ + * Description : Bootsecteur en syntaxe AT&T + * Auteurs : Thomas Petazzoni & Fabrice Gautier & Emmanuel Marty + * Jerome Petazzoni & Bernard Cassagne & coffeeman + * David Decotigny + * Bug reports to kos-misc@enix.org + */ + +/* + * But global de ce bootsecteur : + * + * - Initialiser la becane + * - Charger le kernel + * - Passer en mode protege + * - Executer le kernel + * + * Taille restante : Je vous rappelle qu'un bootsecteur ne peut faire + * qu'au maximum 512 octets dont 2 octets obligatoires 0xAA55. Sur + * les 510 octets reellement utilisables, il reste 3 octets dispo (60 + * si on decide d'enlever le BPB un jour) !!! + * + * thomas_petazzoni : - detection des codes d'erreurs de chargement + * David_Decotigny : - Passage en GNU as + * David_Decotigny : - Chargement du noyau au-dela du 1er Mega (taille + * max = 0x9e000 octets = 632ko), pour avoir le + * meme noyau sous grub et avec le bootsecteur + */ + + /* + * Sequence d'operations : + * - Le BIOS charge le bootsect en 0x7c00 (BOOT_ADRESS). On choisit + * la representation 0x7c0:0000 pour que le .org 0 reste valide + * - Le bootsect se deplace de lui-meme en 0x9f000 (COPY_ADRESS). On + * choisit la representation 0x9f00:0000 pour que le .org 0 reste + * valide + * - Le bootsect verifie que le processeur est du type 386+ + * - Il charge le noyau depuis la disquette en memoire a partir de + * 0x1000 (LOAD_ADRESS). Le noyau peut au max tenir sur + * SECTORS_TO_LOAD secteurs + * - Il passe en pmode flat (apres ouverture a20) + * - Il recopie le noyau (situe en LOAD_ADRESS) vers son adresse + * finale (FINAL_ADDRESS = 2Mo). La recopie se fait sur tout l'espace + * LOAD_ADRESS ---> COPY_ADRESS, c'est a dire sur 0x9e000 octets = + * 632ko. Le noyau peut donc au max faire 632ko. Le nombre max de + * secteurs de disquette qu'on peut charger est donc 1264 + */ + + +/* La taille de la pile */ +#define BOOT_STACK_SIZE 0x4000 + + .file "bootsect.S" + + /* Tout est place dans une seule section */ + .section ".bootsect" + + /* L'essentiel du bootsector (sauf les 1eres instructions) + sont a un offset 0. On fait en sorte que le compilo soit + d'accord la-dessus. Quand on a des adresse realm exotiques + (0x7c00, 0x9f000, ...), on s'arrange toujours pour avoir un + offset de 0 => on choisira le segment adapte (0x7c0, + 0x9f00, ...). Il ne faut pas oublier le ld -Ttext 0 */ + .org 0 + + /* Pour que gas genere du 16bits, afin que ca marche en realm */ + .code16 + +#define SECTORS_TO_LOAD 128 /* 64 ko */ /* MAX=1264 */ + +/* + * Parametres de la disquette. Comme c'est chiant de faire une + * procedure de detection auto, et que ca prend de la place, on fait + * ca "a la main". Par exemple, une DD 720 Ko a 9 secteurs/piste, une + * 1.44 Mo a 18 secteurs/pistes + */ +#define CYLS 80 +#define HEADS 1 +#define SECTS 18 + +#define BOOT_ADRESS 0x07C00 /* Adresse de demarrage (lineaire) */ +#define BOOT_SEG (BOOT_ADRESS>>4) /* Segment de Boot */ +#define BOOT_SIZE 512 /* Taille bu bootsecteur */ +#define COPY_ADRESS 0x9F000 /* La ou on va copier le + bootsecteur (lineaire) */ +#define COPY_SEG (COPY_ADRESS>>4) /* Segment de la ou on va + copier le bootsecteur */ +#define LOAD_ADRESS 0x01000 /* 1er chargement du systeme */ +#define LOAD_SEG (LOAD_ADRESS>>4) /* Segment du 1er chargement du */ +#define MAX_KERN_LEN COPY_ADRESS-LOAD_ADRESS /* Taille noyau maxi */ + +/* IMPORTANT : Cette valeur DOIT etre identique a l'adresse presente + dans sos.lds ! */ +#define FINAL_ADDRESS 0x200000 /* Adresse finale (physique de 0 a 4G) + ou est charge le noyau */ + +#define OP16 .byte 0x66 ; +#define OP32 .byte 0x66 ; + +/* + * Procedure qui vide le buffer clavier. + */ +#define WAITKB \ + 1: ;\ + .word 0xeb ;\ + .word 0xeb ;\ + inb $0x64, %al ;\ + andb $0x2, %al ;\ + jnz 1b + + /* Le point d'entree dans le bootsect */ +.globl _bsect +_bsect: + + /* + * La portion qui suit est situee a un offset 0x7c00 en + * memoire. Attention donc aux references memoire dans cette + * partie. On choisit de rester en offset 0 (.org 0), mais on + * charge correctement les segments a 0x7c0. + */ + + movw $BOOT_SEG, %ax /* le bootsecteur est a 0x7C00 en lineaire */ + movw %ax, %ds /* on le copie a l'adresse COPY_ADRESS */ + xorw %si, %si /* comme cette adresse est la plus haute de la mem */ + xorw %di, %di /* on pourra charger un kernel + gros */ + movw $(BOOT_SIZE>>1), %cx + movw $COPY_SEG, %ax + movw %ax, %es + cld + rep ; movsw + + /* on continue a executer le bootsecteur, mais maintenant a + partir de 0x9F000, qu'on represente sous la forme + 0x9f00:offset */ + ljmp $COPY_SEG, $here + + /* + * A partir de maintenant, on est a un offset 0 en memoire + * (segment 0x9f00), conformement a ce que veut le compilo. + */ +here: + movw %ax, %ds + + /* Petite pile temporaire (1k - 3.84k en RAM ; les adresses 0-1k + correspondent au vecteur d'interruptions). */ + movw %ax, %ss + movw $(LOAD_ADRESS - 0x10), %sp + + /* Efface l'ecran */ + movb $0x0, %ah + movb $0x3, %al + int $0x10 + + /* Affiche les messages d'attente */ + movw $loadkern, %si + call message + movw $check, %si + call message + +check386: + /* + * la attention, plus complexe : on teste si le proc est un + * 386+ pour cela, on va essayer de modifier les bits 12 ? 14 + * du registre E-flag si la modification reste, alors le proc + * est un 386+, sinon, c'est =< 286 + * + * Merci a Emmanuel Marty pour la compatibilite avec les 386 + * "pre-jurassique" + */ + + pushf /* on sauvegarde le E-Flag */ + movb $0x70, %ah + pushw %ax + popf + pushf + popw %ax + orb %ah, %ah + je no386 /* si la modif n'est pas valable, alors on saute a + no386 */ + popf /* on les restaure ? la fin ... */ + + /* Message de confirmation de 386+ et d'attente */ + movw $found386, %si + call message + movw $loading, %si + call message + +/* Copie du noyau disquette => RAM a partir de 0x1000 + L'adresse de destination est définie par es:0, où es vaut + initialement 0x100 (ie correspond alors à l'adresse 256*16, soit 4 + ko). Chaque itération incrémente ce registre es de 32, ce qui + correspond à un bond de 32*16 en mémoire, soit la taille d'un + secteur. De cette façon, puisqu'on joue sur les segments plutôt que + sur les offsets, la taille du noyau n'est pas limitée à 64 ko. Elle + est limitée par contre à la taille de la mémoire disponible sous + les 1Mo, \ie 640 ko (0x9f000 - 0x1000). */ +copyKernel: + /* Chargement du noyau en LOAD_SEG:0 */ + /* 3 iterateurs : + - load_size : le nbre de secteurs a charger + - cl : le secteur ou on en est pour le + cylindre en cours (<= SECTS) + - dh : la tete en cours (0/1) + */ + movb $0, %dl + movw $LOAD_SEG, %ax + movw %ax, %es + + xorw %bx, %bx + xorw %dx, %dx + movw $1, %cx /* premier secteur */ + +.nextsector: /* prochain secteur */ + incb %cl /* en incrementant CL */ + cmpb $SECTS, %cl /* si CL =< SECTS (=nbre de secteurs/pistes) + alors on charge */ + jbe .sector + movb $1, %cl /* sinon on revient au secteur 1 */ + incb %dh /* mais sur l'autre tete */ + cmpb $1, %dh /* on recompare, si DH =< 1 */ + je .sector /* on charge */ + movb $0, %dh /* sinon on repasse a la tete 0 */ + incb %ch /* mais on change de cylindre */ + +.sector: + pushw %es + movw $0x0201, %ax /* service 0x2, chargement 0x1 seecteur */ + int $0x13 /* Go ! */ + jc halt /* erreur */ + popw %ax + addw $32, %ax /* on a charge un secteur, donc on doit + charger 512 bytes plus loin */ + movw %ax, %es /* on avance donc le segment du buffer de + 32bytes, ie 1 secteur en RAM (car 32*16=512) */ + + movw $(0x0E*256+'.'), %ax /* affiche un point */ + int $0x10 + + decw (load_size) /* et on repart pour le prochain secteur + tant qu'on n'a pas fini ! */ + jnz .nextsector + +after: + movw $0x03f2, %dx + inb %dx, %al /* stoppe le moteur */ + andb $0x0f, %al + outb %al, %dx + + cli /* on interdit les interruptions */ + +fincopie: + pushw %cs + popw %ds + + /* on ouvre la porte A20 */ + WAITKB /* on vide le buffer */ + movb $0xd1, %al /* on met a jour le port */ + outb %al, $0x64 + WAITKB + movb $0xdf, %al /* bit 2 = ouverture/fermeture */ + outb %al, $0x60 + + /* + * init gdt + */ +InitGDT: + /* Préparation du flat mode */ + lgdt gdtr + +GoPMode: + /* Passage en mode protégé */ + movl %cr0, %eax + orb $1, %al /* set PE bit to 1 */ + movl %eax, %cr0 + + /* we are not yet in Pmode jump 'in' pmode clearing prefetch + * queue and loading a new selector */ + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + +/* + * Code 32 bits ============================================================ + */ + .code32 + +JumpToHere32: /* Se deplace a l'endroit actuel, en passant en 32bits + et en utilisant la gdt, et vide la prefetch queue */ + .byte 0x66 /* Prefixe 32bits : en realite, jusqu'au jmp, on est + encore en 16 bits */ + ljmp $0x8, $(COPY_ADRESS+(Here32)) +Here32: + /* Et voila : On est en 32 bits vrai */ + +MoveKernelToFinalAddr: /* Deplace le noyau (en LOAD_ADDRESS) vers sa + destination finale (FINAL_ADDRESS) */ + movl $0x10, %eax + movl %eax, %ds /* Seg Src = DSeg */ + movl %eax, %es /* Sed Dest = DSeg */ + cld + movl $LOAD_ADRESS, %esi /* On commence la copie au debut du noyau */ + movl $FINAL_ADDRESS, %edi /* On copie vers cette adresse */ + movl $MAX_KERN_LEN, %ecx /* Taille recopie */ + shrl $2, %ecx + rep + movsl + +LaunchKernel: + /* Met en place une pile au niveau du symbole "stack" */ + movl %eax, %ss + movl $(stack + BOOT_STACK_SIZE), %ebp + movl %ebp, %esp + + /* Saut vers le noyau. La GDT est en place (flat mode), les + * selecteurs aussi, a20 est ouverte, et les interruptions sont + * cli + pas de idt. Le PIC n'est pas programme */ + ljmp $0x8, $sos_main + +/* + * Utilities ============================================================ + */ + .code16 + +message: + lodsb /* charge ds:si dans al et incremente si */ + orb %al, %al /* si al = 0 */ + jz 1f + movb $0x0e, %ah /* service 0Eh (affichage d'un caractere) */ + movw $0x0007, %bx /* Parametres : blanc sur fond noir */ + int $0x10 /* Appel de l'interruption 10h */ + jmp message /* On repart au début ... */ + 1: ret /* si la chaine est finie alors on retourne + dans la fonction appelante */ + +halt: + pushw %cs + popw %es + movw $haltmsg, %si + call message + cli + 1: jmp 1b + ret + +no386: + movw $need386, %si + call message + call halt + + /* + * GDT + */ + +gdt: +gdtr: +NULL_Desc: + .word (EndGDT)-(gdt)-1 /* Taille GDT */ + .long (gdt)+COPY_ADRESS +unused: + .word 0 + +CS_Desc: /* 0x8 */ + .word 0xFFFF, 0 + .byte 0, 0x9B, 0xCF, 0 + +DS_Desc: /* 0x10 */ + .word 0xFFFF, 0 + .byte 0, 0x93, 0xCF, 0 + +EndGDT: + + /* quelques messages */ + +loadkern: .string "-= S O S =- : The Simple Operating System \r\n" +check: .string "Checking for a 386+ processor... " +found386: .string " [OK]\r\n" +need386: .string " [FAILED]\r\n" +diskerror: .string "Disk Error\r\n" +loading: .string "Loading... " +haltmsg: .string "System Halted\r\n" + +/*** Les code/données du boot secteur se terminent ICI. le marqueur de + * fin (aa55) est ajouté automatiquement par le script ld + * sos_bsect.lds ***/ + +/* La pile de 16k qu'on utilise au niveau de LaunchKernel se trouve + declaree avec le noyau, dans sa section ".bss", cad HORS du boot + secteur ! (sinon ca depasserait 512B, forcément). On aurait pu la + définir directement dans le sos_bsect.lds, ou dans un fichier .c + auxiliaire pour plus de clarté */ +.comm stack, BOOT_STACK_SIZE diff --git a/sos-code-article2/extra/dot.mkvars b/sos-code-article2/extra/dot.mkvars new file mode 100644 index 0000000..1f7dca5 --- /dev/null +++ b/sos-code-article2/extra/dot.mkvars @@ -0,0 +1,29 @@ +# For cross-compilation and/or installations without grub available, +# copy this file as .mkvars to the root directory of the SOS sources, +# and customize the CC/LD/... variables. You still need the mtools +# installed and running + +CC := i586-gnu-gcc +LD := i586-gnu-ld +OBJCOPY := i586-gnu-objcopy +CFLAGS += -O3 + +# Configuration of mtools +MTOOLSRC = extra/mtoolsrc +export MTOOLSRC + +$(MULTIBOOT_IMAGE): $(KERNEL_OBJ) menu.txt + gzip -dc < extra/grub.img.gz > $@ + mcopy menu.txt v:/boot/grub/ + mmd v:/system + mcopy sos.elf v:/system/sos.elf + +menu.txt: + echo timeout 0 > $@ + echo default 0 >> $@ + echo title SOS >> $@ + echo "root (fd0)" >> $@ + echo kernel /system/sos.elf >> $@ + +runbochs: all + echo c | bochs -q diff --git a/sos-code-article2/extra/grub.img.gz b/sos-code-article2/extra/grub.img.gz Binary files differnew file mode 100644 index 0000000..4f98e74 --- /dev/null +++ b/sos-code-article2/extra/grub.img.gz diff --git a/sos-code-article2/extra/mtoolsrc b/sos-code-article2/extra/mtoolsrc new file mode 100644 index 0000000..df1a26e --- /dev/null +++ b/sos-code-article2/extra/mtoolsrc @@ -0,0 +1,2 @@ +# For older versions of mtools, you may have to remove "filter" +drive v: file="fd.img" 1.44M filter diff --git a/sos-code-article2/extra/qemu-port-e9.diff b/sos-code-article2/extra/qemu-port-e9.diff new file mode 100644 index 0000000..d8be044 --- /dev/null +++ b/sos-code-article2/extra/qemu-port-e9.diff @@ -0,0 +1,73 @@ +--- Makefile.target 17 Mar 2004 23:46:04 -0000 1.19 ++++ Makefile.target 18 Mar 2004 14:20:29 -0000 +@@ -217,7 +217,8 @@ + # must use static linking to avoid leaving stuff in virtual address space + VL_OBJS=vl.o osdep.o block.o monitor.o \ + ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ +- fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o ++ fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o \ ++ port-e9.o + ifeq ($(TARGET_ARCH), ppc) + VL_OBJS+= hw.o + endif +--- hw/pc.c 14 Mar 2004 21:46:48 -0000 1.2 ++++ hw/pc.c 18 Mar 2004 14:20:29 -0000 +@@ -371,6 +371,7 @@ + SB16_init(); + + fdctrl_init(6, 2, 0, 0x3f0, fd_table); ++ port_e9_init(); + + cmos_init(ram_size, boot_device); + } +--- /dev/null 2003-01-30 11:24:37.000000000 +0100 ++++ port-e9.c 2004-03-18 15:18:52.660493187 +0100 +@@ -0,0 +1,38 @@ ++/* ++ * QEMU Port 0xe9 hack ++ * ++ * Copyright (c) 2000-2004 E. Marty, the bochs team, D. Decotigny ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++#include <stdio.h> ++#include <unistd.h> ++#include <inttypes.h> ++ ++#include "vl.h" ++ ++static void bochs_e9_write(void *opaque, uint32_t address, uint32_t data) ++{ ++ write(fileno(stdout), &data, 1); ++} ++ ++void port_e9_init () ++{ ++ register_ioport_write(0xe9, 1, 1, bochs_e9_write, NULL); ++} +--- vl.h 17 Mar 2004 23:17:16 -0000 1.14 ++++ vl.h 18 Mar 2004 14:29:06 -0000 +@@ -268,4 +268,7 @@ + void term_flush(void); + void term_print_help(void); + ++/* port-e9.c */ ++void port_e9_init(void); ++ + #endif /* VL_H */ diff --git a/sos-code-article2/extra/sos_bsect.lds b/sos-code-article2/extra/sos_bsect.lds new file mode 100644 index 0000000..ac42f23 --- /dev/null +++ b/sos-code-article2/extra/sos_bsect.lds @@ -0,0 +1,61 @@ +/* Copyright (C) 2004, David Decotigny + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +SECTIONS +{ + /* *********************************************** + * The bootsector is here. We link it against the remaining of the kernel + * in order to automatically figure out its size that must be loaded + * from file to memory (see the load_size definition below) + */ + + /* If we use one, we put the boot sector here. We don't set its + * address to 0x7c000 (aka 0x7c00:0), since it reloads itself to + * 0x9f000, causing the 0x7c000 address to be meaningless too. So we + * chose to pretend that the address is 0x0, and to make a little + * address arithmetic in bootsect.S */ + .bootsect 0x0 : + { + /* The code for the boot sector goes here */ + *(.bootsect); + + /* The load_size symbol contains the size of the area (in + * sectors, aka 512 Bytes) that the boot sector should copy from + * the disk. The bss section is not included since it uses 0 + * bytes on disk */ + load_size = .; + LONG((__e_load - __b_load + 511) >> 9); + /* ---> This is equivalent to ceil( (__e_load - __b_load) / 512 ) */ + + /* At offsets 511 and 512, we set the boot sector signature (AA55h) */ + . = 0x1fe; + SHORT(0xAA55); + } +} + + +/* This is to avoid a cut/paste here. Please notice that a multiboot + * section WILL be inserted, which is NOT mandatory (we could have + * removed it without getting into trouble). Please note however that + * the *.bin files will NOT be multiboot compatible (they are not in ELF + * format): they are expected to be directly booted by the BIOS (or + * by the "chainloader" command of Grub). */ +INCLUDE ../support/sos.lds + +/* We overload the entry set in sos.lds, just to avoid an ld warning */ +ENTRY(sos_main); diff --git a/sos-code-article2/hwcore/exception.c b/sos-code-article2/hwcore/exception.c new file mode 100644 index 0000000..9ab5aff --- /dev/null +++ b/sos-code-article2/hwcore/exception.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "idt.h" +#include "irq.h" + +#include "exception.h" + +/* array of exception wrappers, defined in exception_wrappers.S */ +extern sos_vaddr_t sos_exception_wrapper_array[SOS_EXCEPT_NUM]; + +/* arrays of exception handlers, shared with exception_wrappers.S */ +sos_exception_handler_t sos_exception_handler_array[SOS_EXCEPT_NUM] = + { NULL, }; + +sos_ret_t sos_exceptions_setup(void) +{ + /* We inidicate that the double fault exception handler is defined, + and give its address. this handler is a do-nothing handler (see + exception_wrappers.S), and it can NOT be overriden by the + functions below */ + return sos_idt_set_handler(SOS_EXCEPT_BASE + SOS_EXCEPT_DOUBLE_FAULT, + (sos_vaddr_t) sos_exception_wrapper_array[SOS_EXCEPT_DOUBLE_FAULT], + 0 /* CPL0 routine */); +} + + +sos_ret_t sos_exception_set_routine(int exception_number, + sos_exception_handler_t routine) +{ + sos_ret_t retval; + sos_ui32_t flags; + + if ((exception_number < 0) || (exception_number >= SOS_EXCEPT_NUM)) + return -SOS_EINVAL; + + /* Double fault not supported */ + if (exception_number == SOS_EXCEPT_DOUBLE_FAULT) + return -SOS_ENOSUP; + + sos_disable_IRQs(flags); + + retval = SOS_OK; + + /* Set the exception routine to be called by the exception wrapper */ + sos_exception_handler_array[exception_number] = routine; + + /* If the exception is to be enabled, update the IDT with the exception + wrapper */ + if (routine != NULL) + retval + = sos_idt_set_handler(SOS_EXCEPT_BASE + exception_number, + (sos_vaddr_t) sos_exception_wrapper_array[exception_number], + 0 /* CPL0 routine */); + else /* Disable the IDT entry */ + retval + = sos_idt_set_handler(SOS_EXCEPT_BASE + exception_number, + (sos_vaddr_t)NULL /* No routine => disable IDTE */, + 0 /* don't care */); + + sos_restore_IRQs(flags); + return retval; +} + + +sos_exception_handler_t sos_exception_get_routine(int exception_number) +{ + if ((exception_number < 0) || (exception_number >= SOS_EXCEPT_NUM)) + return NULL; + + /* Double fault not supported */ + if (exception_number == SOS_EXCEPT_DOUBLE_FAULT) + return NULL; + + /* Expected to be atomic */ + return sos_exception_handler_array[exception_number]; +} diff --git a/sos-code-article2/hwcore/exception.h b/sos-code-article2/hwcore/exception.h new file mode 100644 index 0000000..7e52fe5 --- /dev/null +++ b/sos-code-article2/hwcore/exception.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_HWEXCEPT_H_ +#define _SOS_HWEXCEPT_H_ + +/** + * @file exception.c + * + * Hardware exception routines management. + */ + +#ifndef ASM_SOURCE +# include <sos/errno.h> +#endif + +/** + * Standard Intel x86 exceptions. + * + * @see Intel x86 doc vol 3, section 5.12. + */ +#define SOS_EXCEPT_DIVIDE_ERROR 0 // No error code +#define SOS_EXCEPT_DEBUG 1 // No error code +#define SOS_EXCEPT_NMI_INTERRUPT 2 // No error code +#define SOS_EXCEPT_BREAKPOINT 3 // No error code +#define SOS_EXCEPT_OVERFLOW 4 // No error code +#define SOS_EXCEPT_BOUND_RANGE_EXCEDEED 5 // No error code +#define SOS_EXCEPT_INVALID_OPCODE 6 // No error code +#define SOS_EXCEPT_DEVICE_NOT_AVAILABLE 7 // No error code +#define SOS_EXCEPT_DOUBLE_FAULT 8 // Yes (Zero) +#define SOS_EXCEPT_COPROCESSOR_SEGMENT_OVERRUN 9 // No error code +#define SOS_EXCEPT_INVALID_TSS 10 // Yes +#define SOS_EXCEPT_SEGMENT_NOT_PRESENT 11 // Yes +#define SOS_EXCEPT_STACK_SEGMENT_FAULT 12 // Yes +#define SOS_EXCEPT_GENERAL_PROTECTION 13 // Yes +#define SOS_EXCEPT_PAGE_FAULT 14 // Yes +#define SOS_EXCEPT_INTEL_RESERVED_1 15 // No +#define SOS_EXCEPT_FLOATING_POINT_ERROR 16 // No +#define SOS_EXCEPT_ALIGNEMENT_CHECK 17 // Yes (Zero) +#define SOS_EXCEPT_MACHINE_CHECK 18 // No +#define SOS_EXCEPT_INTEL_RESERVED_2 19 // No +#define SOS_EXCEPT_INTEL_RESERVED_3 20 // No +#define SOS_EXCEPT_INTEL_RESERVED_4 21 // No +#define SOS_EXCEPT_INTEL_RESERVED_5 22 // No +#define SOS_EXCEPT_INTEL_RESERVED_6 23 // No +#define SOS_EXCEPT_INTEL_RESERVED_7 24 // No +#define SOS_EXCEPT_INTEL_RESERVED_8 25 // No +#define SOS_EXCEPT_INTEL_RESERVED_9 26 // No +#define SOS_EXCEPT_INTEL_RESERVED_10 27 // No +#define SOS_EXCEPT_INTEL_RESERVED_11 28 // No +#define SOS_EXCEPT_INTEL_RESERVED_12 29 // No +#define SOS_EXCEPT_INTEL_RESERVED_13 30 // No +#define SOS_EXCEPT_INTEL_RESERVED_14 31 // No + +#ifndef ASM_SOURCE + +typedef void (*sos_exception_handler_t)(int exception_number); + +sos_ret_t sos_exceptions_setup(void); +sos_ret_t sos_exception_set_routine(int exception_number, + sos_exception_handler_t routine); +sos_exception_handler_t sos_exception_get_routine(int exception_number); +#endif /* ! ASM_SOURCE */ + +#endif /* _SOS_HWEXCEPT_H_ */ diff --git a/sos-code-article2/hwcore/exception_wrappers.S b/sos-code-article2/hwcore/exception_wrappers.S new file mode 100644 index 0000000..2f7665c --- /dev/null +++ b/sos-code-article2/hwcore/exception_wrappers.S @@ -0,0 +1,197 @@ +/* Copyright (C) 2004 The KOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "exception.h" + +.file "exception_wrappers.S" + +.text + +/* The address of the table of handlers (defined in exception.c) */ +.extern sos_exception_handler_array + +/* The address of the table of wrappers (defined below, and shared + with exception.c */ +.globl sos_exception_wrapper_array + + +/** + * For exceptions with/without error code, refer to Intel x86 doc vol 3, + * section 5.12 + */ + +/* These wrappers are for exceptions without error code */ +.irp id, \ + SOS_EXCEPT_DIVIDE_ERROR, \ + SOS_EXCEPT_DEBUG, \ + SOS_EXCEPT_NMI_INTERRUPT, \ + SOS_EXCEPT_BREAKPOINT, \ + SOS_EXCEPT_OVERFLOW, \ + SOS_EXCEPT_BOUND_RANGE_EXCEDEED, \ + SOS_EXCEPT_INVALID_OPCODE, \ + SOS_EXCEPT_DEVICE_NOT_AVAILABLE, \ + SOS_EXCEPT_COPROCESSOR_SEGMENT_OVERRUN, \ + SOS_EXCEPT_INTEL_RESERVED_1, \ + SOS_EXCEPT_FLOATING_POINT_ERROR, \ + SOS_EXCEPT_MACHINE_CHECK, \ + SOS_EXCEPT_INTEL_RESERVED_2, \ + SOS_EXCEPT_INTEL_RESERVED_3, \ + SOS_EXCEPT_INTEL_RESERVED_4, \ + SOS_EXCEPT_INTEL_RESERVED_5, \ + SOS_EXCEPT_INTEL_RESERVED_6, \ + SOS_EXCEPT_INTEL_RESERVED_7, \ + SOS_EXCEPT_INTEL_RESERVED_8, \ + SOS_EXCEPT_INTEL_RESERVED_9, \ + SOS_EXCEPT_INTEL_RESERVED_10, \ + SOS_EXCEPT_INTEL_RESERVED_11, \ + SOS_EXCEPT_INTEL_RESERVED_12, \ + SOS_EXCEPT_INTEL_RESERVED_13, \ + SOS_EXCEPT_INTEL_RESERVED_14 + + .p2align 2, 0x90 + sos_exception_wrapper_\id: + .type sos_exception_wrapper_\id,@function + + /* Fake error code */ + pushl $0 + /* Backup the context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Call the handler with exception number as + * argument */ + pushl $\id + leal sos_exception_handler_array,%edi + call *\id*4(%edi) + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + + popl %ebp + /* Remove fake error code */ + addl $4, %esp + iret +.endr + + /* These wrappers are for exceptions with error code */ +.irp id, \ + SOS_EXCEPT_INVALID_TSS, \ + SOS_EXCEPT_SEGMENT_NOT_PRESENT, \ + SOS_EXCEPT_STACK_SEGMENT_FAULT, \ + SOS_EXCEPT_GENERAL_PROTECTION, \ + SOS_EXCEPT_PAGE_FAULT, \ + SOS_EXCEPT_ALIGNEMENT_CHECK + + .p2align 2, 0x90 + sos_exception_wrapper_\id: + .type sos_exception_wrapper_\id,@function + + /* ret eflags */ + /* ret cs */ + /* ret eip */ + /* Error code */ + + /* Backup the context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Call the handler with exception number as + * argument */ + pushl $\id + leal sos_exception_handler_array,%edi + call *\id*4(%edi) + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + + /* Error code isn't compatible with iretd */ + addl $4, %esp + + iret +.endr + + +/* Double fault handler not supported. We must define it since we + define an entry for it in the sos_exception_wrapper_array. */ +.irp id, SOS_EXCEPT_DOUBLE_FAULT +.p2align 2, 0x90 +sos_exception_wrapper_\id: +.type sos_exception_wrapper_\id,@function +1: hlt + jmp 1b /* Machine halting */ +.endr + +/* Build the sos_irq_wrapper_array, shared with interrupt.c */ +.section ".rodata" +.p2align 5, 0x0 +sos_exception_wrapper_array: + .irp id, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, \ + 16,17,18,19,20,21,22,23,24,25,26,27,29,30,31 + .long (sos_exception_wrapper_\id) + .endr diff --git a/sos-code-article2/hwcore/gdt.c b/sos-code-article2/hwcore/gdt.c new file mode 100644 index 0000000..7945c8c --- /dev/null +++ b/sos-code-article2/hwcore/gdt.c @@ -0,0 +1,150 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "segment.h" + +#include "gdt.h" + + +/** + * The sructure of a segment descriptor. + * + * @see Intel x86 doc, Vol 3, section 3.4.3, figure 3-8. For segment + * types, see section 3.5 + */ +struct x86_segment_descriptor +{ + /* Lowest dword */ + sos_ui16_t limit_15_0; /* Segment limit, bits 15..0 */ + sos_ui16_t base_paged_addr_15_0; /* Base address, bits 15..0 */ + + /* Highest dword */ + sos_ui8_t base_paged_addr_23_16; /* Base address bits 23..16 */ + sos_ui8_t segment_type:4; /* Section 3.4.3.1 (code/data) + and 3.5 (system) of Intel x86 vol 3 */ + sos_ui8_t descriptor_type:1; /* 0=system, 1=Code/Data */ + sos_ui8_t dpl:2; + sos_ui8_t present:1; + + sos_ui8_t limit_19_16:4; /* Segment limit, bits 19..16 */ + sos_ui8_t custom:1; + sos_ui8_t zero:1; + sos_ui8_t op_size:1; /* 0=16bits instructions, 1=32bits */ + sos_ui8_t granularity:1; /* 0=limit in bytes, 1=limit in pages */ + + sos_ui8_t base_paged_addr_31_24; /* Base address bits 31..24 */ +} __attribute__ ((packed, aligned (8))); + + +/** + * The GDT register, which stores the address and size of the + * GDT. + * + * @see Intel x86 doc vol 3, section 2.4, figure 2-4; and section + * 3.5.1 + */ +struct x86_gdt_register { + /* The maximum GDT offset allowed to access an entry in the GDT */ + sos_ui16_t limit; + + /* This is not exactly a "virtual" address, ie an adddress such as + those of instructions and data; this is a "linear" address, ie an + address in the paged memory. However, in SOS we configure the + segmented memory as a "flat" space: the 0-4GB segment-based (ie + "virtual") addresses directly map to the 0-4GB paged memory (ie + "linear"), so that the "linear" addresses are numerically equal + to the "virtual" addresses: this base_addr will thus be the same + as the address of the gdt array */ + sos_ui32_t base_addr; +} __attribute__((packed, aligned(8))); + + +/** + * Helper macro that builds a Segment descriptor for the virtual + * 0..4GB addresses to be mapped to the linear 0..4GB linear + * addresses. + */ +#define BUILD_GDTE(descr_privilege_level,is_code) \ + ((struct x86_segment_descriptor) { \ + .limit_15_0= 0xffff, \ + .base_paged_addr_15_0= 0, \ + .base_paged_addr_23_16= 0, \ + .segment_type= ((is_code)?0xb:0x3), \ + /* With descriptor_type (below) = 1 (code/data), \ + * see Figure 3-1 of section 3.4.3.1 in Intel \ + * x86 vol 3: \ + * - Code (bit 3 = 1): \ + * bit 0: 1=Accessed \ + * bit 1: 1=Readable \ + * bit 2: 0=Non-Conforming \ + * - Data (bit 3 = 0): \ + * bit 0: 1=Accessed \ + * bit 1: 1=Writable \ + * bit 2: 0=Expand up (stack-related) \ + * For Conforming/non conforming segments, see \ + * Intel x86 Vol 3 section 4.8.1.1 \ + */ \ + .descriptor_type= 1, /* 1=Code/Data */ \ + .dpl= ((descr_privilege_level) & 0x3), \ + .present= 1, \ + .limit_19_16= 0xf, \ + .custom= 0, \ + .op_size= 1, /* 32 bits instr/data */ \ + .granularity= 1 /* limit is in 4kB Pages */ \ + }) + + +/** The actual GDT */ +static struct x86_segment_descriptor gdt[] = { + [SOS_SEG_NULL] = (struct x86_segment_descriptor){ 0, }, + [SOS_SEG_KCODE] = BUILD_GDTE(0, 1), + [SOS_SEG_KDATA] = BUILD_GDTE(0, 0), +}; + +sos_ret_t sos_gdt_setup(void) +{ + struct x86_gdt_register gdtr; + + /* Address of the GDT */ + gdtr.base_addr = (sos_ui32_t) gdt; + + /* The limit is the maximum offset in bytes from the base address of + the GDT */ + gdtr.limit = sizeof(gdt) - 1; + + /* Commit the GDT into the CPU, and update the segment + registers. The CS register may only be updated with a long jump + to an absolute address in the given segment (see Intel x86 doc + vol 3, section 4.8.1). */ + asm volatile ("lgdt %0 \n\ + ljmp %1,$1f \n\ + 1: \n\ + movw %2, %%ax \n\ + movw %%ax, %%ss \n\ + movw %%ax, %%ds \n\ + movw %%ax, %%es \n\ + movw %%ax, %%fs \n\ + movw %%ax, %%gs" + : + :"m"(gdtr), + "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE)), + "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA)) + :"memory","eax"); + + return SOS_OK; +} diff --git a/sos-code-article2/hwcore/gdt.h b/sos-code-article2/hwcore/gdt.h new file mode 100644 index 0000000..b7e3f4c --- /dev/null +++ b/sos-code-article2/hwcore/gdt.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_GDT_H_ +#define _SOS_GDT_H_ + +/** + * @file gdt.h + * + * The routines that manage the GDT, the table that maps the virtual + * addresses (data/instructions, segment-relative), to "linear" + * addresses (ie paged-memory). In SOS/x86, we use a "flat" virtual + * space, ie the virtual and linear spaces are equivalent. + * + * @see Intel x86 doc vol 3, chapter 3 + */ + +#include <sos/errno.h> + +/** + * Configure the virtual space as a direct mapping to the linear + * address space (ie "flat" virtual space). + */ +sos_ret_t sos_gdt_setup(void); + +#endif /* _SOS_GDT_H_ */ diff --git a/sos-code-article2/hwcore/i8254.c b/sos-code-article2/hwcore/i8254.c new file mode 100644 index 0000000..5fbb156 --- /dev/null +++ b/sos-code-article2/hwcore/i8254.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2004 The KOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <hwcore/ioports.h> + +#include "i8254.h" + +/** 82c54 clock frequency */ +#define I8254_MAX_FREQ 1193180 + +/* Ports to communicate with the 82c54 */ +#define I8254_TIMER0 0x40 +#define I8254_TIMER1 0x41 +#define I8254_TIMER2 0x42 +#define I8254_CONTROL 0x43 + +/** + * Configure the first timer of the 82c54 chip as a rate generator, + * which will raise an IRQ0 on a regular periodic basis, as given by + * the freq parameter. Second (RAM refresh) and third (speaker) timers + * are left unchanged. Maximum frequency is that of the 8254 clock, ie + * 1193180 Hz. + * + * Ahhh PC systems are nice toys: this maximum "strange" frequency + * equals that of the NTSC clock (14.31818 MHz) divided by 12. In + * turn, the famous 4.77 MHz cpu clock frequency of the first IBM PC + * is this same NTSC frequency divided by 3. Why the NTSC frequency as + * a base "standard" ? Because the 14.31818 MHz quartz were cheap at + * that time, and because it allows to simply drive altogether the + * cpu, the "time of day" timer, and the video signal generators. + */ +sos_ret_t sos_i8254_set_frequency(unsigned int freq) +{ + unsigned int nb_tick; + + if (freq <= 0) + return -SOS_EINVAL; + + /* Compute counter value */ + nb_tick = I8254_MAX_FREQ / freq; + + /* Counter must be between 1 and 65536 */ + if (nb_tick > 65536) + return -SOS_EINVAL; + if (nb_tick <= 0) + return -SOS_EINVAL; + + /* The i8254 interprets 0 to mean counter == 65536, because 65536 + cannot be coded on 16bits */ + if (nb_tick == 65536) + nb_tick = 0; + + /* We want to configure timer0, we want to send both LSB+MSB to set + timer0 freq (-> 0x30), and we configure timer0 in mode 2, ie as a + rate generator (-> 0x4) ==> 0x34 */ + outb(0x34, I8254_CONTROL); + + /* Send LSB of counter first */ + outb((nb_tick & 0xFF), I8254_TIMER0); + + /* Send MSB of counter */ + outb((nb_tick >> 8) & 0xFF, I8254_TIMER0); + + return SOS_OK; +} diff --git a/sos-code-article2/hwcore/i8254.h b/sos-code-article2/hwcore/i8254.h new file mode 100644 index 0000000..4838ff4 --- /dev/null +++ b/sos-code-article2/hwcore/i8254.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_i8259_H_ +#define _SOS_i8259_H_ + +#include <sos/errno.h> + +/** + * @file i8254.h PC programmable timer + * + * Programmable timer routines. See the Intel 82C54 datasheet (on kos + * website). + * + * @see i82C54 datasheet on Kos website. + */ + +/** Change timer interrupt (IRQ 0) frequency */ +sos_ret_t sos_i8254_set_frequency(unsigned int freq); + +#endif /* _SOS_i8259_H_ */ diff --git a/sos-code-article2/hwcore/i8259.c b/sos-code-article2/hwcore/i8259.c new file mode 100644 index 0000000..8391c07 --- /dev/null +++ b/sos-code-article2/hwcore/i8259.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2004 The KOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "ioports.h" + +#include "i8259.h" + +#define PIC_MASTER 0x20 +#define PIC_SLAVE 0xa0 + +/** Setup the 8259 PIC */ +sos_ret_t sos_i8259_setup(void) +{ + /* Send ICW1: 8086 mode + NOT Single ctrl + call address + interval=8 */ + outb(0x11, PIC_MASTER); + outb(0x11, PIC_SLAVE); + + /* Send ICW2: ctrl base address */ + outb(0x20, PIC_MASTER+1); + outb(0x28, PIC_SLAVE+1); + + /* Send ICW3 master: mask where slaves are connected */ + outb(0x4, PIC_MASTER+1); + /* Send ICW3 slave: index where the slave is connected on master */ + outb(0x2, PIC_SLAVE+1); + + /* Send ICW4: 8086 mode, fully nested, not buffered, no implicit EOI */ + outb(0x1, PIC_MASTER+1); + outb(0x1, PIC_SLAVE+1); + + /* Send OCW1: + * Closing all IRQs : waiting for a correct handler The only IRQ + * enabled is the cascade (that's why we use 0xFB for the master) */ + outb(0xFB, PIC_MASTER+1); + outb(0xFF, PIC_SLAVE+1); + + return SOS_OK; +} + + +sos_ret_t sos_i8259_enable_irq_line(int numirq) +{ + if(numirq < 8) + /* irq on master PIC */ + outb((inb(PIC_MASTER+1) & ~(1 << numirq)), PIC_MASTER+1); + else + /* irq on slave PIC */ + outb((inb(PIC_SLAVE+1) & ~(1 << (numirq-8))), PIC_SLAVE+1); + + return SOS_OK; +} + + +sos_ret_t sos_i8259_disable_irq_line(int numirq) +{ + if(numirq < 8) + /* irq on master PIC */ + outb((inb(PIC_MASTER+1) | (1 << numirq)), PIC_MASTER+1); + else + /* irq on slave PIC */ + outb((inb(PIC_SLAVE+1) | (1 << (numirq-8))), PIC_SLAVE+1); + + return SOS_OK; +} diff --git a/sos-code-article2/hwcore/i8259.h b/sos-code-article2/hwcore/i8259.h new file mode 100644 index 0000000..c1771dd --- /dev/null +++ b/sos-code-article2/hwcore/i8259.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_i8259_H_ +#define _SOS_i8259_H_ + +#include <sos/errno.h> + +/** + * @file i8259.h PIC + * + * PIC Management routines. See the Intel 8259A datasheet (on kos + * website), page 9+. Should be not be used directly: only interrupt.c + * should use this. + * + * @see i8259A datasheet on Kos website. + */ + +/** Setup PIC and Disable all IRQ lines */ +sos_ret_t sos_i8259_setup(void); + +sos_ret_t sos_i8259_enable_irq_line(int numirq); + +sos_ret_t sos_i8259_disable_irq_line(int numirq); + +#endif /* _SOS_i8259_H_ */ diff --git a/sos-code-article2/hwcore/idt.c b/sos-code-article2/hwcore/idt.c new file mode 100644 index 0000000..51e3a9d --- /dev/null +++ b/sos-code-article2/hwcore/idt.c @@ -0,0 +1,160 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "segment.h" + +#include "idt.h" + +/** + * An entry in the IDT, or "IDTE" in the following, ie a reference to + * a interrupt/trap routine or a task gate to handle the sw/hw + * interrupts and exceptions. + * + * @see figure 5-2, intel x86 doc, vol 3 + */ +struct x86_idt_entry +{ + /* Low dword */ + sos_ui16_t offset_low; /* 15..0, offset of the routine in the segment */ + sos_ui16_t seg_sel; /* 31..16, the ID of the segment */ + + /* High dword */ + sos_ui8_t reserved:5; /* 4..0 */ + sos_ui8_t flags:3; /* 7..5 */ + sos_ui8_t type:3; /* 10..8 (interrupt gate, trap gate...) */ + sos_ui8_t op_size:1; /* 11 (0=16bits instructions, 1=32bits instr.) */ + sos_ui8_t zero:1; /* 12 */ + sos_ui8_t dpl:2; /* 14..13 */ + sos_ui8_t present:1; /* 15 */ + sos_ui16_t offset_high; /* 31..16 */ +} __attribute__((packed)); + + +/** + * The IDT register, which stores the address and size of the + * IDT. + * + * @see Intel x86 doc vol 3, section 2.4, figure 2-4 + */ +struct x86_idt_register +{ + /* The maximum GDT offset allowed to access an entry in the GDT */ + sos_ui16_t limit; + + /* This is not exactly a "virtual" address, ie an adddress such as + those of instructions and data; this is a "linear" address, ie an + address in the paged memory. However, in SOS we configure the + segmented memory as a "flat" space: the 0-4GB segment-based (ie + "virtual") addresses directly map to the 0-4GB paged memory (ie + "linear"), so that the "linear" addresses are numerically equal + to the "virtual" addresses: this base_addr will thus be the same + as the address of the gdt array */ + sos_ui32_t base_addr; +} __attribute__((packed, aligned (8))); + + +static struct x86_idt_entry idt[SOS_IDTE_NUM]; + +sos_ret_t sos_idt_setup() +{ + struct x86_idt_register idtr; + int i; + + for (i = 0 ; + i < SOS_IDTE_NUM ; + i++) + { + struct x86_idt_entry *idte = idt + i; + + /* Setup an empty IDTE interrupt gate, see figure 5-2 in Intel + x86 doc, vol 3 */ + idte->seg_sel = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE); + idte->reserved = 0; + idte->flags = 0; + idte->type = 0x6; /* Interrupt gate (110b) */ + idte->op_size = 1; /* 32bits instructions */ + idte->zero = 0; + + /* Disable this IDT entry for the moment */ + sos_idt_set_handler(i, (sos_vaddr_t)NULL, 0/* Don't care */); + } + + /* + * Setup the IDT register, see Intel x86 doc vol 3, section 5.8. + */ + + /* Address of the IDT */ + idtr.base_addr = (sos_ui32_t) idt; + + /* The limit is the maximum offset in bytes from the base address of + the IDT */ + idtr.limit = sizeof(idt) - 1; + + /* Commit the IDT into the CPU */ + asm volatile ("lidt %0\n"::"m"(idtr):"memory"); + + return SOS_OK; +} + + +sos_ret_t sos_idt_set_handler(int index, + sos_vaddr_t handler_address, + int lowest_priviledge /* 0..3 */) +{ + struct x86_idt_entry *idte; + + if ((index < 0) || (index >= SOS_IDTE_NUM)) + return -SOS_EINVAL; + if ((lowest_priviledge < 0) || (lowest_priviledge > 3)) + return -SOS_EINVAL; + + idte = idt + index; + if (handler_address != (sos_vaddr_t)NULL) + { + idte->offset_low = handler_address & 0xffff; + idte->offset_high = (handler_address >> 16) & 0xffff; + idte->dpl = lowest_priviledge; + idte->present = 1; /* Yes, there is a handler */ + } + else /* Disable this IDT entry */ + { + idte->offset_low = 0; + idte->offset_high = 0; + idte->dpl = 0; + idte->present = 0; /* No, there is no handler */ + } + + return SOS_OK; +} + + +sos_ret_t sos_idt_get_handler(int index, + sos_vaddr_t *handler_address, + int *lowest_priviledge) +{ + if ((index < 0) || (index >= SOS_IDTE_NUM)) + return -SOS_EINVAL; + + if (handler_address != NULL) + *handler_address = idt[index].offset_low + | (idt[index].offset_high << 16); + if (lowest_priviledge != NULL) + *lowest_priviledge = idt[index].dpl; + + return SOS_OK; +} diff --git a/sos-code-article2/hwcore/idt.h b/sos-code-article2/hwcore/idt.h new file mode 100644 index 0000000..7afe364 --- /dev/null +++ b/sos-code-article2/hwcore/idt.h @@ -0,0 +1,85 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_IDT_H_ +#define _SOS_IDT_H_ + +/** + * @file idt.h + * + * Manage the x86 Interrupt Descriptor Table, the table which maps the + * hardware interrupt lines, hardware exceptions, and software + * interrupts, to software routines. We only define "interrupt gate" + * IDT entries. Don't use it directly; refer instead to interrupt.c, + * exceptions.c and syscall.c. + * + * @see Intel x86 doc, Vol 3, chapter 5 + */ + +#include <sos/errno.h> +#include <sos/types.h> + +/* Mapping of the CPU exceptions in the IDT (imposed by Intel + standards) */ +#define SOS_EXCEPT_BASE 0 +#define SOS_EXCEPT_NUM 32 +#define SOS_EXCEPT_MAX (SOS_HWEXCEPT_BASE + SOS_HWEXCEPT_NUM - 1) + +/* Mapping of the IRQ lines in the IDT */ +#define SOS_IRQ_BASE 32 +#define SOS_IRQ_NUM 16 +#define SOS_IRQ_MAX (SOS_IRQ_BASE + SOS_IRQ_NUM - 1) + +/** + * Number of IDT entries. + * + * @note Must be large enough to map the hw interrupts, the exceptions + * (=> total is 48 entries), and the syscall(s). Since our syscall + * will be 0x42, it must be >= 0x43. Intel doc limits this to 256 + * entries, we use this limit. + */ +#define SOS_IDTE_NUM 256 /* 0x100 */ + +/** Initialization routine: all the IDT entries (or "IDTE") are marked + "not present". */ +sos_ret_t sos_idt_setup(void); + +/** + * Enable the IDT entry if handler_address != NULL, with the given + * lowest_priviledge.\ Disable the IDT entry when handler_address == + * NULL (the lowest_priviledge parameter is then ignored). Intel doc + * says that there must not be more than 256 entries. + * + * @note IRQ Unsafe + */ +sos_ret_t sos_idt_set_handler(int index, + sos_vaddr_t handler_address, + int lowest_priviledge /* 0..3 */); + + +/** + * @note IRQ Unsafe + * + * @return the handler address and DPL in the 2nd and 3rd + * parameters + */ +sos_ret_t sos_idt_get_handler(int index, + sos_vaddr_t *handler_address, + int *lowest_priviledge); + +#endif /* _SOS_IDT_H_ */ diff --git a/sos-code-article2/hwcore/ioports.h b/sos-code-article2/hwcore/ioports.h new file mode 100644 index 0000000..443acb7 --- /dev/null +++ b/sos-code-article2/hwcore/ioports.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2004 All GPL'ed OS + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_IOPORTS_H_ +#define _SOS_IOPORTS_H_ + +/** + * @ioports.h + * + * Intel-specific I/O space access routines. + */ + +/* This macro allows to write to an I/O port */ +#define outb(value, port) \ + __asm__ volatile ( \ + "outb %b0,%w1" \ + ::"a" (value),"Nd" (port) \ + ) \ + +// read one byte from port +#define inb(port) \ +({ \ + unsigned char _v; \ + __asm__ volatile ( \ + "inb %w1,%0" \ + :"=a" (_v) \ + :"Nd" (port) \ + ); \ + _v; \ +}) + +#endif /* _SOS_IOPORTS_H_ */ diff --git a/sos-code-article2/hwcore/irq.c b/sos-code-article2/hwcore/irq.c new file mode 100644 index 0000000..6ec3371 --- /dev/null +++ b/sos-code-article2/hwcore/irq.c @@ -0,0 +1,91 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "idt.h" +#include "i8259.h" + +#include "irq.h" + +/* array of IRQ wrappers, defined in irq_wrappers.S */ +extern sos_vaddr_t sos_irq_wrapper_array[SOS_IRQ_NUM]; + +/* arrays of IRQ handlers, shared with irq_wrappers.S */ +sos_irq_handler_t sos_irq_handler_array[SOS_IRQ_NUM] = { NULL, }; + + +sos_ret_t sos_irq_setup(void) +{ + return sos_i8259_setup(); +} + + +sos_ret_t sos_irq_set_routine(int irq_level, + sos_irq_handler_t routine) +{ + sos_ret_t retval; + sos_ui32_t flags; + + if ((irq_level < 0) || (irq_level >= SOS_IRQ_NUM)) + return -SOS_EINVAL; + + sos_disable_IRQs(flags); + + retval = SOS_OK; + + /* Set the irq routine to be called by the IRQ wrapper */ + sos_irq_handler_array[irq_level] = routine; + + /* If the irq is to be enabled, update the IDT with the IRQ + wrapper */ + if (routine != NULL) + { + retval + = sos_idt_set_handler(SOS_IRQ_BASE + irq_level, + (sos_vaddr_t) sos_irq_wrapper_array[irq_level], + 0 /* CPL0 routine */); + /* A problem occured */ + if (retval != SOS_OK) + sos_irq_handler_array[irq_level] = NULL; + } + else /* Disable this idt entry */ + { + retval + = sos_idt_set_handler(SOS_IRQ_BASE + irq_level, + (sos_vaddr_t)NULL /* Disable IDTE */, + 0 /* Don't care */); + } + + /* Update the PIC only if an IRQ handler has been set */ + if (sos_irq_handler_array[irq_level] != NULL) + sos_i8259_enable_irq_line(irq_level); + else + sos_i8259_disable_irq_line(irq_level); + + sos_restore_IRQs(flags); + return retval; +} + + +sos_irq_handler_t sos_irq_get_routine(int irq_level) +{ + if ((irq_level < 0) || (irq_level >= SOS_IRQ_NUM)) + return NULL; + + /* Expected to be atomic */ + return sos_irq_handler_array[irq_level]; +} diff --git a/sos-code-article2/hwcore/irq.h b/sos-code-article2/hwcore/irq.h new file mode 100644 index 0000000..5b39230 --- /dev/null +++ b/sos-code-article2/hwcore/irq.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_HWINTR_H_ +#define _SOS_HWINTR_H_ + +/** + * @file irq.c + * + * Hardware interrupts routines management. + */ + +#include <sos/errno.h> + +#define sos_save_flags(flags) \ + asm volatile("pushfl ; popl %0":"=g"(flags)::"memory") +#define sos_restore_flags(flags) \ + asm volatile("push %0; popfl"::"g"(flags):"memory") + +#define sos_disable_IRQs(flags) \ + ({ sos_save_flags(flags); asm("cli\n"); }) +#define sos_restore_IRQs(flags) \ + sos_restore_flags(flags) + +/* Usual IRQ levels */ +#define SOS_IRQ_TIMER 0 +#define SOS_IRQ_KEYBOARD 1 +#define SOS_IRQ_SLAVE_PIC 2 +#define SOS_IRQ_COM2 3 +#define SOS_IRQ_COM1 4 +#define SOS_IRQ_LPT2 5 +#define SOS_IRQ_FLOPPY 6 +#define SOS_IRQ_LPT1 7 +#define SOS_IRQ_8_NOT_DEFINED 8 +#define SOS_IRQ_RESERVED_1 9 +#define SOS_IRQ_RESERVED_2 10 +#define SOS_IRQ_RESERVED_3 11 +#define SOS_IRQ_RESERVED_4 12 +#define SOS_IRQ_COPROCESSOR 13 +#define SOS_IRQ_HARDDISK 14 +#define SOS_IRQ_RESERVED_5 15 + +typedef void (*sos_irq_handler_t)(int irq_level); + +/** Setup the PIC */ +sos_ret_t sos_irq_setup(void); + +/** + * If the routine is not NULL, the IDT is setup to call an IRQ + * wrapper upon interrupt, which in turn will call the routine, and + * the PIC is programmed to raise an irq.\ If the routine is + * NULL, we disable the irq line. + */ +sos_ret_t sos_irq_set_routine(int irq_level, + sos_irq_handler_t routine); + +sos_irq_handler_t sos_irq_get_routine(int irq_level); + +#endif /* _SOS_HWINTR_H_ */ diff --git a/sos-code-article2/hwcore/irq_wrappers.S b/sos-code-article2/hwcore/irq_wrappers.S new file mode 100644 index 0000000..cf3355d --- /dev/null +++ b/sos-code-article2/hwcore/irq_wrappers.S @@ -0,0 +1,173 @@ +/* Copyright (C) 2004 The KOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#define ASM_SOURCE 1 + +.file "irq_wrappers.S" + +.text + +/* The address of the table of handlers (defined in irq.c) */ +.extern sos_irq_handler_array + +/* The address of the table of wrappers (defined below, and shared + with irq.c */ +.globl sos_irq_wrapper_array + + +/* These pre-handlers are for IRQ (Master PIC) */ +.irp id, 0,1,2,3,4,5,6,7 + + .p2align 2, 0x90 + + sos_irq_wrapper_\id: + .type sos_irq_wrapper_\id,@function + + /* + * Backup the CPU context + */ + + /* Fake error code */ + pushl $0 + + /* Backup the actual context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Send EOI to PIC. See Intel 8259 datasheet + available on Kos website */ + movb $0x20, %al + outb %al, $0x20 + + /* + * Call the handler with IRQ number as argument + */ + pushl $\id + leal sos_irq_handler_array,%edi + call *\id*4(%edi) + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + + /* Remove fake error code */ + addl $4, %esp + + iret + .endr + + +/* These pre-handlers are for IRQ (Slave PIC) */ +.irp id, 8,9,10,11,12,13,14,15 + + .p2align 2, 0x90 + + sos_irq_wrapper_\id: + .type sos_irq_wrapper_\id,@function + + /* + * Backup the CPU context + */ + + /* Fake error code */ + pushl $0 + + /* Backup the actual context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Send EOI to PIC. See Intel 8259 datasheet + available on Kos website */ + movb $0x20, %al + outb %al, $0xa0 + outb %al, $0x20 + + /* + * Call the handler with IRQ number as argument + */ + pushl $\id + leal sos_irq_handler_array,%edi + call *\id*4(%edi) + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + + /* Remove fake error code */ + addl $4, %esp + + iret + .endr + +/* Build the sos_irq_wrapper_array, shared with irq.c */ +.section ".rodata" +.p2align 5, 0x0 +sos_irq_wrapper_array: + .irp id, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .long (sos_irq_wrapper_\id) + .endr diff --git a/sos-code-article2/hwcore/segment.h b/sos-code-article2/hwcore/segment.h new file mode 100644 index 0000000..37bdf5e --- /dev/null +++ b/sos-code-article2/hwcore/segment.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_HWSEGS_H_ +#define _SOS_HWSEGS_H_ + +/** + * @file segments.h + * + * Global and local (GDT/LDT) segment descriptor definition and + * structure. These segments map virtual addresses (ie + * data/instruction addresses, relative to these segment descriptors) + * to linear addresses (ie addresses in the paged-memory space). + * + * @see Intel x86 doc, vol 3 chapter 3. + */ + +#include <sos/types.h> + +/* + * Global segment selectors (GDT) for SOS/x86. + * + * @see gdt.h + */ +#define SOS_SEG_NULL 0 /* NULL segment, unused by the procesor */ +#define SOS_SEG_KCODE 1 /* Kernel code segment */ +#define SOS_SEG_KDATA 2 /* Kernel data segment */ + + +/** + * Helper macro that builds a segment register's value + */ +#define SOS_BUILD_SEGMENT_REG_VALUE(desc_privilege,in_ldt,seg_index) \ + ( (((desc_privilege) & 0x3) << 0) \ + | (((in_ldt)?1:0) << 2) \ + | ((seg_index) << 3) ) + + +/* + * Local segment selectors (LDT) for SOS/x86 + */ +/* None */ + +#endif /* _SOS_HWSEGS_H_ */ diff --git a/sos-code-article2/sos.elf b/sos-code-article2/sos.elf Binary files differnew file mode 100755 index 0000000..0898db5 --- /dev/null +++ b/sos-code-article2/sos.elf diff --git a/sos-code-article2/sos.map b/sos-code-article2/sos.map new file mode 100644 index 0000000..ea0519f --- /dev/null +++ b/sos-code-article2/sos.map @@ -0,0 +1,106 @@ +00201000 __b_kernel +00200000 __b_load +00202d6b clk_it +00203940 clock_count.1103 +00202ce0 display_bits +00203944 div_count.1107 +00202da3 divide_ex +00207950 __e_kernel +00203066 __e_load +00202f00 gdt +00203080 idt +00201011 loop +0020278b memcmp +00202734 memcpy +00202765 memset +00201000 multiboot_entry +00200000 multiboot_header +00202cab snprintf +00202629 sos_bochs_hexdump +002026ee sos_bochs_printf +0020244b sos_bochs_puthex +00202426 sos_bochs_putstring +0020241c sos_bochs_setup +002012d0 sos_exception_get_routine +00203880 sos_exception_handler_array +0020123d sos_exception_set_routine +00201218 sos_exceptions_setup +00201300 sos_exception_wrapper_0 +00201344 sos_exception_wrapper_1 +002019a4 sos_exception_wrapper_10 +002019e4 sos_exception_wrapper_11 +00201a24 sos_exception_wrapper_12 +00201a64 sos_exception_wrapper_13 +00201aa4 sos_exception_wrapper_14 +00201564 sos_exception_wrapper_15 +002015a8 sos_exception_wrapper_16 +00201ae4 sos_exception_wrapper_17 +002015ec sos_exception_wrapper_18 +00201630 sos_exception_wrapper_19 +00201388 sos_exception_wrapper_2 +00201674 sos_exception_wrapper_20 +002016b8 sos_exception_wrapper_21 +002016fc sos_exception_wrapper_22 +00201740 sos_exception_wrapper_23 +00201784 sos_exception_wrapper_24 +002017c8 sos_exception_wrapper_25 +0020180c sos_exception_wrapper_26 +00201850 sos_exception_wrapper_27 +00201894 sos_exception_wrapper_28 +002018d8 sos_exception_wrapper_29 +002013cc sos_exception_wrapper_3 +0020191c sos_exception_wrapper_30 +00201960 sos_exception_wrapper_31 +00201410 sos_exception_wrapper_4 +00201454 sos_exception_wrapper_5 +00201498 sos_exception_wrapper_6 +002014dc sos_exception_wrapper_7 +00201b24 sos_exception_wrapper_8 +00201520 sos_exception_wrapper_9 +00202f20 sos_exception_wrapper_array +002011e4 sos_gdt_setup +002021a8 sos_i8254_set_frequency +0020214e sos_i8259_disable_irq_line +002020f0 sos_i8259_enable_irq_line +002020a0 sos_i8259_setup +00201174 sos_idt_get_handler +002010b9 sos_idt_set_handler +00201014 sos_idt_setup +00201bfe sos_irq_get_routine +00203900 sos_irq_handler_array +00201b35 sos_irq_set_routine +00201b28 sos_irq_setup +00201c20 sos_irq_wrapper_0 +00201c68 sos_irq_wrapper_1 +00201ef0 sos_irq_wrapper_10 +00201f38 sos_irq_wrapper_11 +00201f80 sos_irq_wrapper_12 +00201fc8 sos_irq_wrapper_13 +00202010 sos_irq_wrapper_14 +00202058 sos_irq_wrapper_15 +00201cb0 sos_irq_wrapper_2 +00201cf8 sos_irq_wrapper_3 +00201d40 sos_irq_wrapper_4 +00201d88 sos_irq_wrapper_5 +00201dd0 sos_irq_wrapper_6 +00201e18 sos_irq_wrapper_7 +00201e60 sos_irq_wrapper_8 +00201ea8 sos_irq_wrapper_9 +00202fa0 sos_irq_wrapper_array +00202ddb sos_main +00202240 sos_x86_videomem_cls +0020238a sos_x86_videomem_printf +00202313 sos_x86_videomem_putchar +00202283 sos_x86_videomem_putstring +00202220 sos_x86_videomem_setup +00203950 stack +00201000 start +00201000 _start +002028d9 strcmp +002027e5 strlen +0020291b strncmp +0020280a strnlen +0020288e strzcat +0020283d strzcpy +00202f18 video +0020297c vsnprintf diff --git a/sos-code-article2/sos/assert.h b/sos-code-article2/sos/assert.h new file mode 100644 index 0000000..a14ca0b --- /dev/null +++ b/sos-code-article2/sos/assert.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2004 The KOS Team + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_ASSERT_H_ +#define _SOS_ASSERT_H_ + +#include <drivers/bochs.h> +#include <drivers/x86_videomem.h> + +/** + * If the expr is FALSE, print a message and halt the machine + */ +#define SOS_ASSERT_FATAL(expr) \ + ({ \ + int __res=(int)(expr); \ + if (! __res) { \ + asm("cli\n"); /* disable interrupts -- x86 only */ \ + sos_bochs_printf("%s@%s:%d Assertion " # expr " failed\n", \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + sos_x86_videomem_printf(24, 0, 12, \ + "%s@%s:%d Assertion " # expr " failed", \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + for (;;) asm("hlt;") ; /* Infinite loop, ie simple system halt */ \ + } \ + }) + + +#endif /* _SOS_ASSERT_H_ */ diff --git a/sos-code-article2/sos/errno.h b/sos-code-article2/sos/errno.h new file mode 100644 index 0000000..f13e740 --- /dev/null +++ b/sos-code-article2/sos/errno.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_ERRNO_H_ +#define _SOS_ERRNO_H_ + +/** + * @file errno.h + * + * SOS return value codes and errors. + */ + +/* Positive values of the error codes */ +#define SOS_OK 0 /* No error */ +#define SOS_EINVAL 1 /* Invalid argument */ +#define SOS_ENOSUP 2 /* Operation not supported */ +#define SOS_EFATAL 255 /* Internal fatal error */ + +/* A negative value means that an error occured. For + * example -SOS_EINVAL means that the error was "invalid + * argument" */ +typedef int sos_ret_t; + +#endif /* _SOS_ERRNO_H_ */ diff --git a/sos-code-article2/sos/klibc.c b/sos-code-article2/sos/klibc.c new file mode 100644 index 0000000..277a15c --- /dev/null +++ b/sos-code-article2/sos/klibc.c @@ -0,0 +1,271 @@ +/* Copyright (C) 2004 David Decotigny (with INSA Rennes for vsnprintf) + Copyright (C) 2003 The KOS Team + Copyright (C) 1999 Free Software Foundation + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "klibc.h" + +/* For an optimized version, see BSD sources ;) */ +void *memcpy(void *dst0, const void *src0, register unsigned int size) +{ + char *dst; + const char *src; + for (dst = (char*)dst0, src = (const char*)src0 ; + size > 0 ; + dst++, src++, size--) + *dst = *src; + return dst0; +} + +/* ditto */ +void *memset(void *dst0, register int c, register unsigned int length) +{ + char *dst; + for (dst = (char*) dst0 ; + length > 0 ; + dst++, length --) + *dst = (char)c; + return dst0; +} + +int memcmp(const void *s1, const void *s2, sos_size_t len) +{ + const unsigned char *c1, *c2; + unsigned int i; + + for (i = 0, c1 = s1, c2 = s2; i < len; i++, c1++, c2++) + { + if(*c1 != *c2) + return *c1 - *c2; + } + + return 0; +} + + +unsigned int strlen(register const char *str) +{ + unsigned int retval = 0; + + while (*str++) + retval++; + + return retval; +} + + +unsigned int strnlen(const char * s, sos_size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */continue; + + return sc - s; +} + + +char *strzcpy(register char *dst, register const char *src, register int len) +{ + int i; + + if (len <= 0) + return dst; + + for (i = 0; i < len; i++) + { + dst[i] = src[i]; + if(src[i] == '\0') + return dst; + } + + dst[len-1] = '\0'; + return dst; +} + + +char *strzcat (char *dest, const char *src, sos_size_t n) +{ + char *res = dest; + + for ( ; *dest ; dest++); + + for ( ; *src ; src++, dest++) { + *dest = *src; + n--; + if (n <= 0) + break; + } + + *dest = '\0'; + return res; +} + +int strcmp(register const char *s1, register const char *s2) +{ + while (*s1 == *s2++) + if (*s1++ == 0) + return (0); + + return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); +} + + +int strncmp(register const char *s1, register const char *s2, register int len) +{ + char c1 = '\0', c2 = '\0'; + + while (len > 0) + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + len--; + } + + return c1 - c2; +} + + +/* I (d2) borrowed and rewrote this for Nachos/INSA Rennes. Thanks to + them for having kindly allowed me to do so. */ +int vsnprintf(char *buff, sos_size_t len, const char * format, va_list ap) +{ + sos_size_t i, result; + + if (!buff || !format || (len < 0)) + return -1; + +#define PUTCHAR(thechar) \ + do { \ + if (result < len-1) \ + *buff++ = (thechar); \ + result++; \ + } while (0) + + result = 0; + for(i=0 ; format[i] != '\0' ; i++){ + switch (format[i]) + { + case '%': + i++; + switch(format[i]) + { + case '%': + { + PUTCHAR('%'); + break; + } + case 'i':; + case 'd': + { + int integer = va_arg(ap,int); + int cpt2 = 0; + char buff_int[16]; + + if (integer<0) + PUTCHAR('-'); + /* Ne fait pas integer = -integer ici parce que INT_MIN + n'a pas d'equivalent positif (int = [-2^31, 2^31-1]) */ + + do { + int m10 = integer%10; + m10 = (m10 < 0)? -m10:m10; + buff_int[cpt2++]=(char)('0'+ m10); + integer=integer/10; + } while(integer!=0); + + for(cpt2 = cpt2 - 1 ; cpt2 >= 0 ; cpt2--) + PUTCHAR(buff_int[cpt2]); + + break; + } + + case 'c': + { + int value = va_arg(ap,int); + PUTCHAR((char)value); + break; + } + + case 's': + { + char *string = va_arg(ap,char *); + if (! string) + string = "(null)"; + for( ; *string != '\0' ; string++) + PUTCHAR(*string); + break; + } + + case 'x': + { + unsigned int hexa = va_arg(ap,int); + unsigned int nb; + int i, had_nonzero = 0; + for(i=0 ; i < 8 ; i++) + { + nb = (unsigned int)(hexa << (i*4)); + nb = (nb >> 28) & 0xf; + // Skip the leading zeros + if (nb == 0) + { + if (had_nonzero) + PUTCHAR('0'); + } + else + { + had_nonzero = 1; + if (nb < 10) + PUTCHAR('0'+nb); + else + PUTCHAR('a'+(nb-10)); + } + } + if (! had_nonzero) + PUTCHAR('0'); + break; + } + break; + + default: + PUTCHAR('%'); + PUTCHAR(format[i]); + } + break; + + default: + PUTCHAR(format[i]); + } + } + + *buff = '\0'; + return result; +} + + +int snprintf(char * buff, sos_size_t len, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + len = vsnprintf(buff, len, format, ap); + va_end(ap); + + return len; +} diff --git a/sos-code-article2/sos/klibc.h b/sos-code-article2/sos/klibc.h new file mode 100644 index 0000000..a8b9d49 --- /dev/null +++ b/sos-code-article2/sos/klibc.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2003 The KOS Team + Copyright (C) 1999 Free Software Foundation + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_KLIBC_H_ +#define _SOS_KLIBC_H_ + +/** + * @file klibc.h + * + * Basic libc-style support for common useful functions (string.h, + * stdarg.h), some with slight non-standard behavior (see comments). + */ + +#include <sos/types.h> + +/* string.h functions */ + +void *memcpy(void *dst, const void *src, register unsigned int size ) ; +void *memset(void *dst, register int c, register unsigned int length ) ; +int memcmp(const void *s1, const void *s2, sos_size_t n); + +unsigned int strlen( register const char *str) ; +unsigned int strnlen(const char * s, sos_size_t maxlen); + +/** + * @note Same as strncpy(), with a slightly different semantic. + * Actually, strncpy(3C) says " The result will not be null-terminated + * if the length of 'from' is n or more.". Here, 'dst' is ALWAYS + * null-terminated. And its total len will ALWAYS be <= len, with + * null-terminating-char included. + */ +char *strzcpy( register char *dst, register const char *src, + register int len ) ; + +/** + * @note Same as strncat(), with the same semantic : 'dst' is ALWAYS + * null-terminated. And its total len will ALWAYS be <= len, with + * null-terminating-char included. + */ +char *strzcat (char *dest, const char *src, + const sos_size_t len); + +int strcmp(register const char *s1, register const char *s2 ); +int strncmp(register const char *s1, register const char *s2, + register int len ); + +/* Basic stdarg.h macros. Taken from gcc support files */ +#define __GNUC_VA_LIST +typedef void *__gnuc_va_list; +typedef __gnuc_va_list va_list; +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) +#define va_start(AP, LASTARG) \ + (AP = ((__gnuc_va_list) __builtin_next_arg (LASTARG))) +#define va_end(AP) \ + ((void)0) +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE)))) +#define __va_copy(dest, src) \ + (dest) = (src) + +/* stdarg.h functions. There might be a non-standard behavior: there + will always be a trailing '\0' in the resulting string */ +int vsnprintf(char *, sos_size_t, const char *, va_list); +int snprintf(char *, sos_size_t, const char *, /*args*/ ...) + __attribute__ ((format (printf, 3, 4))); + +#endif /* _SOS_KLIBC_H_ */ diff --git a/sos-code-article2/sos/main.c b/sos-code-article2/sos/main.c new file mode 100644 index 0000000..9d897b0 --- /dev/null +++ b/sos-code-article2/sos/main.c @@ -0,0 +1,152 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +/* Include definitions of the multiboot standard */ +#include <bootstrap/multiboot.h> +#include <hwcore/idt.h> +#include <hwcore/gdt.h> +#include <hwcore/irq.h> +#include <hwcore/exception.h> +#include <hwcore/i8254.h> +#include <sos/klibc.h> +#include <sos/assert.h> +#include <drivers/x86_videomem.h> +#include <drivers/bochs.h> + + +/* Helper function to display each bits of a 32bits integer on the + screen as dark or light carrets */ +static void display_bits(unsigned char row, unsigned char col, + unsigned char attribute, + sos_ui32_t integer) +{ + int i; + /* Scan each bit of the integer, MSb first */ + for (i = 31 ; i >= 0 ; i--) + { + /* Test if bit i of 'integer' is set */ + int bit_i = (integer & (1 << i)); + /* Ascii 219 => dark carret, Ascii 177 => light carret */ + unsigned char ascii_code = bit_i?219:177; + sos_x86_videomem_putchar(row, col++, + attribute, + ascii_code); + } +} + + +/* Clock IRQ handler */ +static void clk_it(int intid) +{ + static sos_ui32_t clock_count = 0; + + display_bits(0, 48, + SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE, + clock_count); + clock_count++; + +} + +/* Division by zero exception handler */ +static void divide_ex(int exid) +{ + static sos_ui32_t div_count = 0; + display_bits(0, 0, + SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE, + div_count); + div_count++; +} + +/* The C entry point of our operating system */ +void sos_main(unsigned long magic, unsigned long addr) +{ + unsigned i; + + /* Grub sends us a structure, called multiboot_info_t with a lot of + precious informations about the system, see the multiboot + documentation for more information. */ + multiboot_info_t *mbi; + mbi = (multiboot_info_t *) addr; + + /* Setup bochs and console, and clear the console */ + sos_bochs_setup(); + + sos_x86_videomem_setup(); + sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE); + + /* Greetings from SOS */ + if (magic == MULTIBOOT_BOOTLOADER_MAGIC) + /* Loaded with Grub */ + sos_x86_videomem_printf(1, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)", + "SOS", ',', + (unsigned)(mbi->mem_upper >> 10) + 1, + (unsigned)mbi->mem_upper); + else + /* Not loaded with grub */ + sos_x86_videomem_printf(1, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Welcome to SOS"); + + sos_bochs_putstring("Message in a bochs\n"); + + /* Setup CPU segmentation and IRQ subsystem */ + sos_gdt_setup(); + sos_idt_setup(); + + /* Setup SOS IRQs and exceptions subsystem */ + sos_exceptions_setup(); + sos_irq_setup(); + + /* Configure the timer so as to raise the IRQ0 at a 100Hz rate */ + sos_i8254_set_frequency(100); + + + /* Binding some HW interrupts and exceptions to software routines */ + sos_irq_set_routine(SOS_IRQ_TIMER, + clk_it); + sos_exception_set_routine(SOS_EXCEPT_DIVIDE_ERROR, + divide_ex); + /* Enabling the HW interrupts here, this will make the timer HW + interrupt call our clk_it handler */ + asm volatile ("sti\n"); + + /* Raise a rafale of 'division by 0' exceptions. All this code is + not really needed (equivalent to a bare "i=1/0;"), except when + compiling with -O3: "i=1/0;" is considered dead code with gcc + -O3. */ + i = 10; + while (1) + { + /* Stupid function call to fool gcc optimizations */ + sos_bochs_printf("i = 1 / %d...\n", i); + i = 1 / i; + } + + /* Will never print this since the "divide by zero" exception always + returns to the faulting instruction (see Intel x86 doc vol 3, + section 5.12), thus re-evaluating the "divide-by-zero" exprssion + and raising the "divide by zero" exception again and again... */ + sos_x86_videomem_putstring(2, 0, + SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE, + "Invisible"); + + return; +} diff --git a/sos-code-article2/sos/types.h b/sos-code-article2/sos/types.h new file mode 100644 index 0000000..b6efae9 --- /dev/null +++ b/sos-code-article2/sos/types.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_TYPES_H_ +#define _SOS_TYPES_H_ + +/** + * @file types.h + * + * SOS basic types definition + */ + +/** Generic virtual address (kernel or user) */ +typedef unsigned int sos_vaddr_t; + +/** Memory size of an object (positive) */ +typedef unsigned int sos_size_t; + +/** Low-level sizes */ +typedef unsigned long int sos_ui32_t; /* 32b unsigned */ +typedef unsigned short int sos_ui16_t; /* 16b unsigned */ +typedef unsigned char sos_ui8_t; /* 8b unsigned */ + +typedef enum { FALSE=0, TRUE } sos_bool_t; + +/** Not a proper type, but highly useful with basic type + manipulations */ +#define NULL ((void*)0) + +#endif /* _SOS_TYPES_H_ */ diff --git a/sos-code-article2/support/build_image.sh b/sos-code-article2/support/build_image.sh new file mode 100755 index 0000000..43929cd --- /dev/null +++ b/sos-code-article2/support/build_image.sh @@ -0,0 +1,215 @@ +#!/bin/sh +# Copyright (C) 2003, David Decotigny + +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# 1) What does it do ? +# +# 1) Check where Grub is installed (lookup_grub) +# 2) Assign some local variables using the shell script arguments. +# a) Argument 1 : the destination (either a file or a drive, like a:) +# b) Argument 2 : the loader (i.e kernel) +# c) Argument 3 : options passed to the loader +# d) Argument 4 : the modules (that can be loaded optionally by Grub) +# 3) Test whether destination is a drive or a file +# 4) Create the directory structure inside the drive +# 5) Copy the loader in the drive +# 6) Generate the 'menu.txt' file used by Grub to generate the boot menu +# 7) Copy all modules +# 8) Copy the menu.txt file +# +# 2) Why is it so complex ? +# Because it must support various Grub/mtools installations and versions +# +# In fact, this shell script is used in the KOS (kos.enix.org) +# project. This operating system consists in a loader and many many +# modules that are linked together at boot time. It is much more +# complex that a simple monolithic kernel. +# +# For your simple monolithic kernel, you only need to give argument 1 +# and 2. + +print_usage () { + echo "Usage: $0 [X:|image] path/to/loader option path/to/modules..." + echo " where X: is a valid floppy drive on your computer" + echo " where image is any file name" + exit 1 +} + +grub_dirs_common="/usr/local/share/grub/i386-freebsd /usr/local/share/grub/i386-pc /usr/share/grub/i386-pc /usr/lib/grub/i386-pc /usr/local/grub /usr/share/grub/i386-redhat /usr/local/src/grub-0.5.94 $HOME/share/grub/i386-pc/" +sbin_grub_path="/usr/local/sbin /usr/sbin /sbin $HOME/sbin" + +PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin +export PATH + +MTOOLSRC=mtoolsrc +export MTOOLSRC + +# Redefined variables +FLOPPY_DRIVE=A: +IMG_FNAME=fd.img + +## +## Format disk image +## +init_image () { + echo "Initialize disk image $IMG_FILE..." + if [ ! -f $IMG_FNAME ] ; then + dd if=/dev/zero of=$IMG_FNAME bs=18k count=80 1>/dev/null 2>&1 + fi + + rm -f $MTOOLSRC + echo "drive u: file=\"$IMG_FNAME\" 1.44M filter" > $MTOOLSRC + + if mformat U: ; then : ; else + rm -f $MTOOLSRC + echo "drive u: file=\"$IMG_FNAME\" 1.44M" > $MTOOLSRC + if mformat U: ; then : ; else + rm -f $MTOOLSRC + echo "drive u: file=\"$IMG_FNAME\"" > $MTOOLSRC + mformat U: + fi + fi +} + + +## +## Format (real) floppy disk +## +init_floppy () { + echo "Formatting floppy..." + mformat $FLOPPY_DRIVE || exit 1 +} + + +lookup_grub () { + # Look for a correct GRUBDIR + for d in $grub_dirs_common ; do + if [ -d $d ] ; then + GRUBDIR=$d + break + fi + done + + # Try to guess with locate + if [ ! -d "$GRUBDIR" ] ; then + GRUBDIR=`locate stage2 | head -1 | xargs dirname 2>/dev/null` + fi + + # Look for a correct sbin/grub + for d in $sbin_grub_path ; do + if [ -x $d/grub ] ; then + SBIN_GRUB=$d/grub + break + fi + done + + if [ -d "$GRUBDIR" -a -x "$SBIN_GRUB" ] ; then + echo "Found correct grub installation in $GRUBDIR" + echo "Found correct /sbin/grub at $SBIN_GRUB" + else + echo "Couldn't find a correct grub installation." + exit 1 + fi +} + +## +## setup_disk [drive] +## => setup disk directory structure / copy files +## +setup_disk () { + echo "Setup destination disk..." + + mmd $1/boot + mmd $1/boot/grub + + if [ -d $GRUBDIR/stage1 ] ; then + mcopy $GRUBDIR/stage1/stage1 $1/boot/grub/ + mcopy $GRUBDIR/stage2/stage2 $1/boot/grub/ + else + mcopy $GRUBDIR/stage1 $1/boot/grub/ + mcopy $GRUBDIR/stage2 $1/boot/grub/ + fi + mmd $1/system + mmd $1/modules + + $SBIN_GRUB --batch <<EOT 1>/dev/null 2>/dev/null || exit 1 +device (fd0) $IMG_FNAME +install (fd0)/boot/grub/stage1 (fd0) (fd0)/boot/grub/stage2 p (fd0)/boot/grub/menu.txt +quit +EOT +} + + + +################################################# +## Real start +## +#[ "$#" -lt 3 ] && print_usage + +lookup_grub + +dest="$1" ; shift +loader_fname="$1" ; shift +options="$1" ; shift +modules="$*" + +# Init destination disk +case x$dest in + x*:) + drive=$dest + IMG_FNAME=$dest + FLOPPY_DRIVE=$dest + init_floppy + ;; + x*) + drive=U: + IMG_FNAME=$dest + init_image + ;; +esac + +# Create directory structure +setup_disk $drive + +# Copy the loader +mcopy -bo $loader_fname $drive/system/`basename $loader_fname` + +# Generate the menu.txt file +rm -f menu.txt +cat <<EOF > menu.txt +timeout 0 +default 0 +title Simple OS +root (fd0) +kernel /system/`basename $loader_fname` $options +EOF + +# Copy the modules +for f in $modules ; do + if [ ! -f $f ] ; then + echo "ERROR: module $f not correctly compiled in." + exit 1 + fi + if ! mcopy -bo $f $drive/modules/`basename $f` ; then + echo "ERROR: module $f could not be transferred to floppy." + exit 1 + fi + echo module /modules/`basename $f` >> menu.txt +done + +# Transfers the menu.txt file to floppy +mcopy -bo menu.txt $drive/boot/grub/ diff --git a/sos-code-article2/support/sos.lds b/sos-code-article2/support/sos.lds new file mode 100644 index 0000000..4d87061 --- /dev/null +++ b/sos-code-article2/support/sos.lds @@ -0,0 +1,107 @@ +/* Copyright (C) 2003, Thomas Petazzoni + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +/* We generate binary in the ELF format */ +OUTPUT_FORMAT("elf32-i386","elf32-i386","elf32-i386"); + +/* The entry point is _start (defined in boot.S) */ +ENTRY(_start) + +/* The architecture is i386 */ +OUTPUT_ARCH("i386") + +SECTIONS +{ + /* our kernel is loaded at 0x200000 */ + . = 0x200000; + __b_load = .; + + /* the multiboot header MUST come early enough in the output + object file */ + .multiboot : + { + /* The multiboot section (containing the multiboot header) + goes here */ + *(.multiboot); + + /* + * With the following line, we force this section to be + * allocated in the output file as soon as possible, no matter + * when the file containing the multiboot header (multiboot.S) + * is compiled. This is to conform to the multiboot spec, which + * says "The Multiboot header must be contained completely + * within the first 8192 bytes of the OS image, and must be + * longword (32-bit) aligned." + */ + LONG(0); + } + + /* Defines a symbol '__b_kernel to mark the start of the kernel + code/data */ + . = ALIGN(4096); + __b_kernel = .; + + /* Beginning of the text section */ + .text ALIGN(4096) : + { + /* This section includes the code */ + *(.text*) + /* Defines the 'etext' and '_etext' at the end */ + PROVIDE(etext = .); + PROVIDE(_etext = .); + } + + /* Beginning of the data section */ + .data . : + { *(.data*) + PROVIDE(edata = .); + PROVIDE(_edata = .); + } + + /* Beginning of the read-only data section */ + .rodata . : + { *(.rodata*) + PROVIDE(erodata = .); + PROVIDE(_erodata = .); + } + /* We take note of the end of the data to load */ + __e_load = .; + + /* Beginning of the BSS section (global uninitialized data) */ + .bss SIZEOF(.rodata) + ADDR(.rodata) : + { *(.bss) + *(COMMON) + PROVIDE(ebss = .); + PROVIDE(_ebss = .); + } + + /* We take note of the end of the kernel */ + __e_kernel = .; + + /* We don't care of the note, indent, comment, etc.. sections + generated by gcc */ + /DISCARD/ :{ + *(.note*) + *(.indent) + *(.comment) + *(.stab) + *(.stabstr) + } + +} + diff --git a/sos-code-article3/INSTALL b/sos-code-article3/INSTALL new file mode 100644 index 0000000..7c7d619 --- /dev/null +++ b/sos-code-article3/INSTALL @@ -0,0 +1,118 @@ + + SOS: A Simple Operating System + + Compilation/Installation/Test instructions + + +Compilation +=========== + +IMPORTANT +--------- + +Don't forget to run 'make clean' before 'make' after you have modified +any source or header file(s). + + +On a x86 host where grub is correctly installed +----------------------------------------------- + +Simply run 'make' + + +On a non-x86 host (without grub of course !) +-------------------------------------------- + +See extra/README + + +On an x86 host without Grub, or with a buggy Grub +------------------------------------------------- + +See extra/README + +How do I know I have a buggy grub installation ? Answer: in the qemu +PC emulator, Grub hangs while loading the kernel + + +Installation +============ + +Nothing special to do besides compiling + + +Test the SOS Kernel +=================== + +On a x86 real machine with Grub installed +----------------------------------------- + + 1st method + => Boot the sos.elf file (append 'kernel=<path_to>sos.elf' in the + menu.lst or type it on Grub's command line) from a hard disk, a + floppy, or from the network + + 2nd method + => Copy the file 'fd.img' to a floppy and boot from it + + +On a x86 real machine without Grub installed +-------------------------------------------- + + 1st method + => see extra/README to compile with the grub floppy image we provide, + copy the file 'fd.img' to a floppy, and boot from it + + 2nd method + => see extra/README to compile with the boot sector we provide (up to + article 2 only), copy the file 'extra/sos_bsect.img' to a floppy, + and boot from it + + +Inside a PC emulator (x86 and non-x86 hosts) +-------------------------------------------- + +Tested on both the bochs emulator (x86/linux, sparc/solaris and +ppc/linux hosts, 'apt-get install bochs-x vgabios' on debian +testing/unstable), and the qemu system emulator (with libsdl +installed: 'apt-get install libsdl1.2-dev' on debian +testing/unstable). + + 1/ Grub is installed on the host (x86 hosts only) + - - - - - - - - - - - - - - - - - - - - - - - - - + + bochs: boot from the file 'fd.img'. Example of a ~/.bochsrc: + floppya: 1_44=/home/d2/sos/fd.img, status=inserted + romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000 + vgaromimage: /usr/share/vgabios/vgabios.bin + megs:63 # 63 Mo de RAM + + qemu: run 'qemu -fda fd.img' + If grub hangs while loading the kernel, please go to method 2/ + + 2/ Grub is not installed (all hosts) + - - - - - - - - - - - - - - - - - - + + See extra/README to generate a floppy image with the Grub floppy + image we provide, and: + + bochs: boot from the file 'fd.img' + + qemu: run 'qemu -fda fd.img' + + 3/ Bonus: boot with the bootsector we provide (all hosts, up to art. 2 ONLY !) + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + See extra/README to generate a floppy image with the boot sector we + provide, and: + + bochs: boot from the file 'extra/sos_bsect.img' + + qemu: run 'qemu -fda extra/sos_qemu.img' + + NOTE: After article 2, this way of booting is not supported: please + use the method 2/ above. + + +-- +David Decotigny diff --git a/sos-code-article3/LICENSE b/sos-code-article3/LICENSE new file mode 100644 index 0000000..60549be --- /dev/null +++ b/sos-code-article3/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) 19yy 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. + + <signature of Ty Coon>, 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/sos-code-article3/Makefile b/sos-code-article3/Makefile new file mode 100644 index 0000000..8e15812 --- /dev/null +++ b/sos-code-article3/Makefile @@ -0,0 +1,44 @@ +CC=gcc +CFLAGS = -Wall -nostdlib -nostdinc -ffreestanding -DKERNEL_SOS +LDFLAGS = --warn-common +OBJECTS = bootstrap/multiboot.o \ + hwcore/idt.o hwcore/gdt.o \ + hwcore/exception.o hwcore/exception_wrappers.o \ + hwcore/irq.o hwcore/irq_wrappers.o hwcore/i8259.o \ + hwcore/i8254.o drivers/x86_videomem.o drivers/bochs.o \ + sos/physmem.o sos/klibc.o sos/main.o + +KERNEL_OBJ = sos.elf +MULTIBOOT_IMAGE = fd.img +PWD := $(shell pwd) + +# Main target +all: $(MULTIBOOT_IMAGE) + +$(MULTIBOOT_IMAGE): $(KERNEL_OBJ) + ./support/build_image.sh $@ $< + +$(KERNEL_OBJ): $(OBJECTS) ./support/sos.lds + $(LD) $(LDFLAGS) -T ./support/sos.lds -o $@ $(OBJECTS) + -nm -C $@ | cut -d ' ' -f 1,3 > sos.map + +-include .mkvars + +# Create objects from C source code +%.o: %.c + $(CC) -I$(PWD) -c $< $(CFLAGS) -o $@ + +# Create objects from assembler (.S) source code +%.o: %.S + $(CC) -I$(PWD) -c $< $(CFLAGS) -DASM_SOURCE=1 -o $@ + +# Clean directory +clean: + $(RM) *.img *.o mtoolsrc *~ menu.txt *.img *.elf *.bin *.map + $(RM) *.log *.out bochs* + $(RM) bootstrap/*.o bootstrap/*~ + $(RM) drivers/*.o drivers/*~ + $(RM) hwcore/*.o hwcore/*~ + $(RM) sos/*.o sos/*~ + $(RM) support/*~ + $(RM) extra/*~ diff --git a/sos-code-article3/README b/sos-code-article3/README new file mode 100644 index 0000000..efbbc89 --- /dev/null +++ b/sos-code-article3/README @@ -0,0 +1,90 @@ + + SOS: A Simple Operating System + + +This is SOS, a Simple Operating System for i386-family +processors. This is as simple as possible to show a way to program a +basic Operating System on real common hardware (PC). The code should +be easily readable and understandable thanks to frequent comments, and +references to external documentation. We chose to implement the basic +features of an OS, thus making design decisions targetting towards +simplicity of understanding, covering most of the OS classical +concepts, but not aiming at proposing yet another full-fledged +competitive OS (Linux is quite good at it). However, for those who +would like to propose some enhancements, we are open to any code +suggestions (patches only, please). And yes, there might be bugs in +the code, so please send us any bug report, and/or patches ! + +The OS comes as a set of articles (in french) to be published in the +journal "Linux Magazine France". Each month, the part of the code +related to the current article's theme is released (see VERSION file), +and the resulting OS can be successfully compiled and run, by booting +it from a floppy on a real machine (tested AMD k7, Cyrix and Intel P4 +pentiums), or through an x86 emulator (bochs or qemu). The resulting +OS is available as a multiboot compliant ELF kernel (sos.elf) and as a +floppy image (fd.img). It provides a very very very basic demo whose +aim is to understand how everything works, not to animate sprites on +the screen with 5:1 dolby sound. + +The initial technical features and lack-of-features of the OS are: + - monolithic kernel, fully interruptible, non-preemptible (big kernel + lock), target machines = i386 PC or better + - compiles on any host where the gcc/binutils toolchain (target + i586-gnu) is available. Can be tested on real i486/pentium + hardware, or on any host that can run an i486/pentium PC emulator + (bochs or qemu) + - kernel loaded by grub, or by a sample bootsector (up to article 2 + ONLY) + - clear separation of physical memory and virtual memory concepts, + even inside the kernel: no identity-mapping of the physical memory + inside the kernel (allows to move virtual mappings of kernel pages + at run-time, eg to free ISA DMA pages, and to avercome the 4G RAM + barrier) + - slab-type kernel memory allocation + - no swap, no reverse mapping + - VERY simple drivers: keyboard, x86 video memory, IDE disks + - logical devices: partitions, FAT filesystem, "hard-coded" + mountpoints only (~ MSDOS) + - no network stack + - user-level features: ELF loader (no shared libraries), processes, + user threads (kernel-level scheduling only), mmap API, basic VFS + +To understand where to look at for what, here is a brief description: + - Makefile: the (ONLY) makefile of the OS. Targets are basically + 'all' and 'clean' + - bootstrap/ directory: code to load the kernel. Both the stuff + needed for a multiboot-compliant loader (eg grub) AND a bootsector + are provided. The bootsector may only be used up to article 2. + - sos/ directory: the entry routine for the kernel (main.c), various + systemwide header files, a set of common useful C routines + ("nano-klibc"), and kernel subsystems (kernel memory management, + etc...) + - hwcore/ directory: Low-level CPU- and kernel-related routines + (interrupt/exception management, translation tables and segment + registers, ...) + - drivers/ directory: basic kernel drivers for various (non CPU) + devices (keyboard, x86 video memory, bochs 0xe9 port, ...). Used + mainly for debugging + - support/ directory: scripts and configuration files to build the + floppy images + - extra/ directory: a set of configuration files to be customized for + non-x86 host installations (yes, we primarily develop SOS on a ppc, for + the x86 target of course), or for grub-less installations. See + README file in this directory. + +The code is licensed under the terms of the GNU GPL version 2 (see +LICENSE file). + +Enjoy ! + + David Decotigny, Thomas Petazzoni, the Kos team + http://sos.enix.org/ + http://david.decotigny.free.fr/ + http://kos.enix.org/~thomas/ + http://kos.enix.org/ + + +-- +David Decotigny + +PS: Made with a Mac. diff --git a/sos-code-article3/VERSION b/sos-code-article3/VERSION new file mode 100644 index 0000000..43273c3 --- /dev/null +++ b/sos-code-article3/VERSION @@ -0,0 +1,11 @@ +SOS -- Simple OS +Copyright (C) 2003,2004 The SOS Team (David Decotigny & Thomas Petazzoni) + +Version "Article 3" -- Physical memory management & physical page allocator + + 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. + + See the LICENSE file included in the distribution. diff --git a/sos-code-article3/bootstrap/multiboot.S b/sos-code-article3/bootstrap/multiboot.S new file mode 100644 index 0000000..4a7c65b --- /dev/null +++ b/sos-code-article3/bootstrap/multiboot.S @@ -0,0 +1,74 @@ +/* Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + + +/* The operating system is booted by Grub, so we almost have nothing + to do to boot it. We only have to conform to the Multiboot + standard, as defined by the Grub documentation */ + +#define ASM 1 +/* The multiboot.h header contains a lot of multiboot standard + definitions */ +#include "multiboot.h" + + /* The multiboot header itself. It must come first. */ +.section ".multiboot" + /* Multiboot header must be aligned on a 4-byte boundary */ + .align 4 +multiboot_header: + /* magic= */ .long MULTIBOOT_HEADER_MAGIC + /* flags= */ .long MULTIBOOT_HEADER_FLAGS + /* checksum= */ .long -(MULTIBOOT_HEADER_MAGIC \ + +MULTIBOOT_HEADER_FLAGS) + /* header_addr= */ .long multiboot_header + /* load_addr= */ .long __b_kernel + /* load_end_addr=*/ .long __e_load + /* bss_end_addr= */ .long __e_kernel + /* entry_addr= */ .long multiboot_entry + +/* Here is the beginning of the code of our operating system */ +.text + +.globl start, _start +start: +_start: +multiboot_entry: + /* Set up a stack */ + movl $(stack + MULTIBOOT_STACK_SIZE), %ebp + movl %ebp, %esp + + /* Set EFLAGS to 0 */ + pushl $0 + /* pop stack into the EFLAGS register */ + popf + + /* Push the magic and the address on the stack, so that they + will be the parameters of the cmain function */ + pushl %ebx + pushl %eax + + /* Call the cmain function (os.c) */ + call EXT_C(sos_main) + + /* Should never get there */ +loop: + hlt + jmp loop + + /* Here is the stack */ +.comm stack, MULTIBOOT_STACK_SIZE diff --git a/sos-code-article3/bootstrap/multiboot.h b/sos-code-article3/bootstrap/multiboot.h new file mode 100644 index 0000000..bee676d --- /dev/null +++ b/sos-code-article3/bootstrap/multiboot.h @@ -0,0 +1,129 @@ +#ifndef __MULTIBOOT_H__ +#define __MULTIBOOT_H__ + +/* multiboot.h - the header for Multiboot */ +/* Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Macros. */ + +/* The magic number for the Multiboot header. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* The flags for the Multiboot header. */ +#define MULTIBOOT_HEADER_FLAGS 0x00010003 + +/* The magic number passed by a Multiboot-compliant boot loader. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* The size of our stack (16KB). */ +#define MULTIBOOT_STACK_SIZE 0x4000 + +#define MULTIBOOT_CMDLINE 4 +#define MULTIBOOT_MODS 8 + +/* C symbol format. HAVE_ASM_USCORE is defined by configure. */ +#ifdef HAVE_ASM_USCORE +# define EXT_C(sym) _ ## sym +#else +# define EXT_C(sym) sym +#endif + +#ifndef ASM +/* Do not include here in boot.S. */ + + + +/* Types. */ + +/* The Multiboot header. */ +typedef struct multiboot_header +{ + unsigned long magic; + unsigned long flags; + unsigned long checksum; + unsigned long header_addr; + unsigned long load_addr; + unsigned long load_end_addr; + unsigned long bss_end_addr; + unsigned long entry_addr; +} multiboot_header_t; + +/* The symbol table for a.out. */ +typedef struct aout_symbol_table +{ + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long reserved; +} aout_symbol_table_t; + +/* The section header table for ELF. */ +typedef struct elf_section_header_table +{ + unsigned long num; + unsigned long size; + unsigned long addr; + unsigned long shndx; +} elf_section_header_table_t; + +/* The Multiboot information. */ +typedef struct multiboot_info +{ + unsigned long flags; + unsigned long mem_lower; + unsigned long mem_upper; + unsigned long boot_device; + unsigned long cmdline; + unsigned long mods_count; + unsigned long mods_addr; + union + { + aout_symbol_table_t aout_sym; + elf_section_header_table_t elf_sec; + } u; + unsigned long mmap_length; + unsigned long mmap_addr; + unsigned long drives_length; + unsigned long drives_addr; +} multiboot_info_t; + +/* The module structure. */ +typedef struct module +{ + unsigned long mod_start; + unsigned long mod_end; + unsigned long string; + unsigned long reserved; +} module_t; + +/* The memory map. Be careful that the offset 0 is base_addr_low + but no size. */ +typedef struct memory_map +{ + unsigned long size; + unsigned long base_addr_low; + unsigned long base_addr_high; + unsigned long length_low; + unsigned long length_high; + unsigned long type; +} memory_map_t; + +void dump_multiboot_info(multiboot_info_t *mbi); + +#endif /* ! ASM */ + +#endif /* __MULTIBOOT_H__ */ diff --git a/sos-code-article3/drivers/bochs.c b/sos-code-article3/drivers/bochs.c new file mode 100644 index 0000000..db18599 --- /dev/null +++ b/sos-code-article3/drivers/bochs.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <hwcore/ioports.h> +#include <sos/klibc.h> + +#include "bochs.h" + +/* This is a special hack that is only useful when running the + operating system under the Bochs emulator. */ +#define SOS_BOCHS_IOPORT 0xe9 + +sos_ret_t sos_bochs_setup(void) +{ + return SOS_OK; +} + + +#define sos_bochs_putchar(chr) \ + outb((chr), SOS_BOCHS_IOPORT) + +sos_ret_t sos_bochs_putstring(const char* str) +{ + for ( ; str && (*str != '\0') ; str++) + sos_bochs_putchar(*str); + + return SOS_OK; +} + + +sos_ret_t sos_bochs_puthex(unsigned val, int nbytes) +{ + unsigned c; + +#define BOCHS_PRTHEX(q) \ + ({ unsigned char r; if ((q) >= 10) r='a'+(q)-10; \ + else r='0'+(q); sos_bochs_putchar(r); }) + + switch (nbytes) + { + case 4: + c = (val >> 24) & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + case 3: + c = (val >> 16) & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + case 2: + c = (val >> 8) & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + case 1: + c = val & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + } + + return SOS_OK; +} + + +sos_ret_t sos_bochs_hexdump(const void* addr, int nbytes) +{ + int offs; + for (offs = 0 ; offs < nbytes ; offs++) + { + const unsigned char *c; + + if ((offs % 16) == 0) + { + sos_bochs_putstring("0x"); + sos_bochs_puthex(offs, 4); + } + + if ((offs % 8) == 0) + sos_bochs_putstring(" "); + + c = (const unsigned char*)(addr + offs); + sos_bochs_puthex(*c, 1); + sos_bochs_putstring(" "); + + if (((offs + 1) % 16) == 0) + sos_bochs_putstring("\n"); + } + + if (offs % 16) + sos_bochs_putstring("\n"); + + return SOS_OK; +} + + +sos_ret_t sos_bochs_printf(const char *format, /* args */...) +{ + char buff[256]; + va_list ap; + + va_start(ap, format); + vsnprintf(buff, sizeof(buff), format, ap); + va_end(ap); + + return sos_bochs_putstring(buff); +} diff --git a/sos-code-article3/drivers/bochs.h b/sos-code-article3/drivers/bochs.h new file mode 100644 index 0000000..310b023 --- /dev/null +++ b/sos-code-article3/drivers/bochs.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_BOCHS_H_ +#define _SOS_BOCHS_H_ + +/** + * @file bochs.h + * + * If you compiled Bochs with the --enable-e9-hack, then any character + * printed to the 0xE9 I/O port is printed to the xterm that is + * running Bochs. This may appear to be a detail, but in fact, this + * functionnality is *VERY* precious for debugging purposes. This + * """driver""" handles this feature. + */ + +#include <sos/errno.h> +#include <sos/types.h> + +sos_ret_t sos_bochs_setup(void); + +sos_ret_t sos_bochs_putstring(const char* str); + +/** Print the least signficant 32 (nbytes == 4), 24 (nbytes == 3), 16 + (nbytes == 2) or 8 (nbytes == 1) bits of val in hexadecimal. */ +sos_ret_t sos_bochs_puthex(unsigned val, int nbytes); + +/** hexdump-style pretty printing */ +sos_ret_t sos_bochs_hexdump(const void* addr, int nbytes); + +/** + * Print the formatted string. Very restricted version of printf(3): + * 1/ can print max 255 chars, 2/ supports only %d/%i, %c, %s, %x + * without any support for flag charachters (eg %08x). + */ +sos_ret_t sos_bochs_printf(const char *format, /* args */...) + __attribute__ ((format (printf, 1, 2))); + +#endif diff --git a/sos-code-article3/drivers/x86_videomem.c b/sos-code-article3/drivers/x86_videomem.c new file mode 100644 index 0000000..cc4b79c --- /dev/null +++ b/sos-code-article3/drivers/x86_videomem.c @@ -0,0 +1,128 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <sos/klibc.h> +#include <hwcore/ioports.h> + +#include "x86_videomem.h" + +/* The text video memory starts at address 0xB8000. Odd bytes are the + ASCII value of the character, even bytes are attribute for the + preceding character. */ +#define VIDEO 0xb8000 + + +/* Console screen size */ +#define LINES 25 +#define COLUMNS 80 + + +/** The structure of a character element in the video memory. @see + http://webster.cs.ucr.edu/AoA DOS edition chapter 23 */ +typedef struct { + unsigned char character; + unsigned char attribute; +} __attribute__ ((packed)) x86_video_mem[LINES*COLUMNS]; + + + +/** The base pointer for the video memory */ +static volatile x86_video_mem *video = (volatile x86_video_mem*)VIDEO; + +sos_ret_t sos_x86_videomem_setup(void) +{ + /* + * Hide cursor. @see Ralf Brown's interrupt (and port) list + * http://www-2.cs.cmu.edu/~ralf/files.html + */ +#define CRT_REG_INDEX 0x3d4 +#define CRT_REG_DATA 0x3d5 + + /* CRT index port => ask for access to register 0xa ("cursor + start") */ + outb(0x0a, CRT_REG_INDEX); + + /* (RBIL Tables 708 & 654) CRT Register 0xa => bit 5 = cursor OFF */ + outb(1 << 5, CRT_REG_DATA); + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_cls(unsigned char attribute) +{ + /* Clears the screen */ + int i; + for(i = 0 ; i < LINES*COLUMNS ; i++) + { + (*video)[i].character = 0; + (*video)[i].attribute = attribute; + } + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_putstring(unsigned char row, unsigned char col, + unsigned char attribute, + const char *str) +{ + unsigned video_offs = row*COLUMNS + col; + + if (video_offs >= LINES*COLUMNS) + return -SOS_EINVAL; + + for ( ; str && *str && (video_offs < LINES*COLUMNS) ; str++, video_offs++) + { + (*video)[video_offs].character = (unsigned char)*str; + (*video)[video_offs].attribute = attribute; + } + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_putchar(unsigned char row, unsigned char col, + unsigned char attribute, + unsigned char c) +{ + unsigned video_offs = row*COLUMNS + col; + + if (video_offs >= LINES*COLUMNS) + return -SOS_EINVAL; + + (*video)[video_offs].character = c; + (*video)[video_offs].attribute = attribute; + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_printf(unsigned char row, unsigned char col, + unsigned char attribute, + const char *format, /* args */...) +{ + char buff[256]; + va_list ap; + + va_start(ap, format); + vsnprintf(buff, sizeof(buff), format, ap); + va_end(ap); + + return sos_x86_videomem_putstring(row, col, attribute, buff); +} diff --git a/sos-code-article3/drivers/x86_videomem.h b/sos-code-article3/drivers/x86_videomem.h new file mode 100644 index 0000000..31a9dfc --- /dev/null +++ b/sos-code-article3/drivers/x86_videomem.h @@ -0,0 +1,98 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_X86_VIDEOMEM_H_ +#define _SOS_X86_VIDEOMEM_H_ + +/** + * @file x86_videomem.h + * + * On x86 PC platforms, the text mode screen memory (and CGA/EGA/VGA + * too) is mapped into physical memory. This file handles access to + * this screen, supposed to be set in text-mode, through this memory + * area. All the functions below print the characters directly to the + * memory, without interpreting the escaped characters (such as \n, + * \r...) + */ + +#include <sos/errno.h> + +/** + * x86 video attributes + * See http://webster.cs.ucr.edu/AoA/DOS/ch23/CH23-1.html + */ +/* Normal and Dark/Light foreground */ +#define SOS_X86_VIDEO_FG_BLACK 0 +#define SOS_X86_VIDEO_FG_DKGRAY 8 +#define SOS_X86_VIDEO_FG_BLUE 1 +#define SOS_X86_VIDEO_FG_LTBLUE 9 +#define SOS_X86_VIDEO_FG_GREEN 2 +#define SOS_X86_VIDEO_FG_LTGREEN 10 +#define SOS_X86_VIDEO_FG_CYAN 3 +#define SOS_X86_VIDEO_FG_LTCYAN 11 +#define SOS_X86_VIDEO_FG_RED 4 +#define SOS_X86_VIDEO_FG_LTRED 12 +#define SOS_X86_VIDEO_FG_MAGENTA 5 +#define SOS_X86_VIDEO_FG_LTMAGENTA 13 +#define SOS_X86_VIDEO_FG_BROWN 6 +#define SOS_X86_VIDEO_FG_YELLOW 14 +#define SOS_X86_VIDEO_FG_LTGRAY 7 +#define SOS_X86_VIDEO_FG_WHITE 15 +/* Background */ +#define SOS_X86_VIDEO_BG_BLACK (0 << 4) +#define SOS_X86_VIDEO_BG_BLUE (1 << 4) +#define SOS_X86_VIDEO_BG_GREEN (2 << 4) +#define SOS_X86_VIDEO_BG_CYAN (3 << 4) +#define SOS_X86_VIDEO_BG_RED (4 << 4) +#define SOS_X86_VIDEO_BG_MAGENTA (5 << 4) +#define SOS_X86_VIDEO_BG_BROWN (6 << 4) +#define SOS_X86_VIDEO_BG_LTGRAY (7 << 4) +/* Blinking */ +#define SOS_X86_VIDEO_FG_BLINKING (1 << 7) + + +/** Setup the video RAM mapping and clear the screen */ +sos_ret_t sos_x86_videomem_setup(void); + +/** Clears the screen and set the background color as given by + attribute */ +sos_ret_t sos_x86_videomem_cls(unsigned char attribute); + +/** Print the string on the scren with the given attribute. Does not + handle scrolling */ +sos_ret_t sos_x86_videomem_putstring(unsigned char row, unsigned char col, + unsigned char attribute, + const char *str); + +/** Print the character on the scren with the given attribute. Does not + handle scrolling */ +sos_ret_t sos_x86_videomem_putchar(unsigned char row, unsigned char col, + unsigned char attribute, + unsigned char c); + +/** + * Print the formatted string. Very restricted version of printf(3): + * 1/ can print max 255 chars, 2/ supports only %d/%i, %c, %s, %x + * without any support for flag charachters (eg %08x). + */ +sos_ret_t sos_x86_videomem_printf(unsigned char row, unsigned char col, + unsigned char attribute, + const char *format, /* args */...) + __attribute__ ((format (printf, 4, 5))); + +#endif /* _SOS_X86_VIDEOMEM_H_ */ diff --git a/sos-code-article3/extra/Makefile b/sos-code-article3/extra/Makefile new file mode 100644 index 0000000..f858aa6 --- /dev/null +++ b/sos-code-article3/extra/Makefile @@ -0,0 +1,40 @@ +OBJCOPY=objcopy + +all: sos_qemu.img + +-include ../.mkvars + +# The image is the simple concatenation of the boot sector and the kernel +# It may be use in bochs or on a real floppy, but NOT in qemu (see below) +sos_bsect.img: bsect.bin sos.bin + cat $^ > $@ + @echo "[31mYou can use the $@ image in bochs or on a real floppy (NOT qemu)[m" + +# For qemu, the trick is to tell it we have *more* than 1440 sectors (720kB). +# Rtherwise the qemu disk geometry will be configured to be that of a 720kB +# floppy, while our boot sector assumes it to be 1.44MB +sos_qemu.img: sos_bsect.img + # Padding with 0s after the bsect/kernel image + cat $< /dev/zero | dd of=$@ bs=1k count=1440 + @echo "[31mYou can use the $@ image in qemu, bochs, or on a real floppy[m" + +# we extract the boot sector from the main ELF binary +bsect.bin: sos_bsect.elf + $(OBJCOPY) -v -O binary -j .bootsect $< $@ + +# we extract the kernel code from the main ELF binary +sos.bin: sos_bsect.elf + $(OBJCOPY) -v -O binary -R .bootsect $< $@ + +# The main ELF binary contains the boot sector and the kernel code +# linked together (hence we deal with a SINGLE image that we split +# above) because they share some symbol definitions +sos_bsect.elf: bootsect.o compile_kernel + $(LD) --warn-common -T ./sos_bsect.lds -o $@ \ + bootsect.o $(wildcard ../hwcore/*.o ../drivers/*.o ../sos/*.o) + +compile_kernel: + $(MAKE) -C .. + +clean: + $(RM) *.img *.elf *.bin *~ *.o *.out diff --git a/sos-code-article3/extra/README b/sos-code-article3/extra/README new file mode 100644 index 0000000..0272f1f --- /dev/null +++ b/sos-code-article3/extra/README @@ -0,0 +1,73 @@ + +Contents of the extra/ directory +================================ + +Data and configuration files to support generation of sos on non-x86 +and/or grub-less hosts: + - dot.mkvars: file to copy as .mkvars in the root directory to + compile on a non-x86 host, and to generate the grub floppy image on + a grub-less host + - grub.img.gz: compressed image of a Grub floppy (without any + kernel). Used by dot.mkvars. + - mtoolsrc: file needed by .mkvars to compile a the floppy image + +Support of a sos-specific boot sector: + - Makefile: rules to compile sos_bsect.img, the floppy image with the + boot sector and the Sos + - bootsect.S: x86 Sos boot sector (GNU as). Depends on sos_bsect.lds + - sos_bsect.lds: ld script to bind the boot sector with the remaining + of the kernel + +Misc: + - qemu-port-e9.diff: patch over qemu to support the bochs "port 0xe9 hack" + + +What you can do with these files +================================ + + +*** Compile SOS from another architecture: +------------------------------------------ + - compile a cross-compiler for the i586-gnu target. This involves + compiling the binutils and gcc. Here are example configuration + options for them: + binutils (replace sparc-cun-solaris with your arch): + ../binutils-2.13/configure --prefix=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/stow/binutils-2.11 --host=sparc-sun-solaris2.7 i586-gnu + make && make install + gcc (ditto): + CFLAGS="-O2 -Dinhibit_libc" ../gcc-3.2/configure --target=i586-gnu --prefix=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/stow/gcc-3.2 --with-as=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/bin/as --with-ld=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/bin/ld --with-gnu-as --with-gnu-ld --enable-languages=c --disable-shared --disable-multilib --disable-nls --enable-threads=single + make && make install + - compile the mtools + - copy dot.mkvars to the root directory of SOS, as ".mkvars" + - customize the CC/LD/... variables to suit your cross-compiler + installatioon + - now you may run make from the SOS root directory, it should + generate the Grub boot floppy image. The following warning is + normal: + .mkvars:16: attention : écrasement des commandes pour la cible « grub-sos.img » + Makefile:92: attention : anciennes commandes ignorées pour la cible « grub-sos.img » + + +*** To compile SOS from an x86 where grub is not or incorrectly installed: +-------------------------------------------------------------------------- + - copy dot.mkvars to the root directory of SOS, as ".mkvars" + - customize the CC/LD/... variables to suit your cross-compiler + installatioon + - now you may run make from the SOS root directory, it should + generate the Grub boot floppy image. The following warning is + normal: + .mkvars:16: attention : écrasement des commandes pour la cible « grub-sos.img » + Makefile:92: attention : anciennes commandes ignorées pour la cible « grub-sos.img » + + +*** To compile SOS with its own bootloader: +------------------------------------------- + - for cross-architecture compilation: see above + - cd to this extra/ directory + - run 'make' + - the floppy image is: sos_bsect.img + NOTE : SOS will not boot correctly this way after article 2 ! + + +-- +David Decotigny diff --git a/sos-code-article3/extra/bootsect.S b/sos-code-article3/extra/bootsect.S new file mode 100644 index 0000000..f01ca20 --- /dev/null +++ b/sos-code-article3/extra/bootsect.S @@ -0,0 +1,393 @@ + +/* + * @(#) $Id: bootsect.S,v 1.6 2004/06/18 07:43:51 d2 Exp $ + * Description : Bootsecteur en syntaxe AT&T + * Auteurs : Thomas Petazzoni & Fabrice Gautier & Emmanuel Marty + * Jerome Petazzoni & Bernard Cassagne & coffeeman + * David Decotigny + * Bug reports to kos-misc@enix.org + */ + +/* + * But global de ce bootsecteur : + * + * - Initialiser la becane + * - Charger le kernel + * - Passer en mode protege + * - Executer le kernel + * + * Taille restante : Je vous rappelle qu'un bootsecteur ne peut faire + * qu'au maximum 512 octets dont 2 octets obligatoires 0xAA55. Sur + * les 510 octets reellement utilisables, il reste 3 octets dispo (60 + * si on decide d'enlever le BPB un jour) !!! + * + * thomas_petazzoni : - detection des codes d'erreurs de chargement + * David_Decotigny : - Passage en GNU as + * David_Decotigny : - Chargement du noyau au-dela du 1er Mega (taille + * max = 0x9e000 octets = 632ko), pour avoir le + * meme noyau sous grub et avec le bootsecteur + */ + + /* + * Sequence d'operations : + * - Le BIOS charge le bootsect en 0x7c00 (BOOT_ADRESS). On choisit + * la representation 0x7c0:0000 pour que le .org 0 reste valide + * - Le bootsect se deplace de lui-meme en 0x9f000 (COPY_ADRESS). On + * choisit la representation 0x9f00:0000 pour que le .org 0 reste + * valide + * - Le bootsect verifie que le processeur est du type 386+ + * - Il charge le noyau depuis la disquette en memoire a partir de + * 0x1000 (LOAD_ADRESS). Le noyau peut au max tenir sur + * SECTORS_TO_LOAD secteurs + * - Il passe en pmode flat (apres ouverture a20) + * - Il recopie le noyau (situe en LOAD_ADRESS) vers son adresse + * finale (FINAL_ADDRESS = 2Mo). La recopie se fait sur tout l'espace + * LOAD_ADRESS ---> COPY_ADRESS, c'est a dire sur 0x9e000 octets = + * 632ko. Le noyau peut donc au max faire 632ko. Le nombre max de + * secteurs de disquette qu'on peut charger est donc 1264 + */ + + +/* La taille de la pile */ +#define BOOT_STACK_SIZE 0x4000 + + .file "bootsect.S" + + /* Tout est place dans une seule section */ + .section ".bootsect" + + /* L'essentiel du bootsector (sauf les 1eres instructions) + sont a un offset 0. On fait en sorte que le compilo soit + d'accord la-dessus. Quand on a des adresse realm exotiques + (0x7c00, 0x9f000, ...), on s'arrange toujours pour avoir un + offset de 0 => on choisira le segment adapte (0x7c0, + 0x9f00, ...). Il ne faut pas oublier le ld -Ttext 0 */ + .org 0 + + /* Pour que gas genere du 16bits, afin que ca marche en realm */ + .code16 + +#define SECTORS_TO_LOAD 128 /* 64 ko */ /* MAX=1264 */ + +/* + * Parametres de la disquette. Comme c'est chiant de faire une + * procedure de detection auto, et que ca prend de la place, on fait + * ca "a la main". Par exemple, une DD 720 Ko a 9 secteurs/piste, une + * 1.44 Mo a 18 secteurs/pistes + */ +#define CYLS 80 +#define HEADS 1 +#define SECTS 18 + +#define BOOT_ADRESS 0x07C00 /* Adresse de demarrage (lineaire) */ +#define BOOT_SEG (BOOT_ADRESS>>4) /* Segment de Boot */ +#define BOOT_SIZE 512 /* Taille bu bootsecteur */ +#define COPY_ADRESS 0x9F000 /* La ou on va copier le + bootsecteur (lineaire) */ +#define COPY_SEG (COPY_ADRESS>>4) /* Segment de la ou on va + copier le bootsecteur */ +#define LOAD_ADRESS 0x01000 /* 1er chargement du systeme */ +#define LOAD_SEG (LOAD_ADRESS>>4) /* Segment du 1er chargement du */ +#define MAX_KERN_LEN COPY_ADRESS-LOAD_ADRESS /* Taille noyau maxi */ + +/* IMPORTANT : Cette valeur DOIT etre identique a l'adresse presente + dans sos.lds ! */ +#define FINAL_ADDRESS 0x200000 /* Adresse finale (physique de 0 a 4G) + ou est charge le noyau */ + +#define OP16 .byte 0x66 ; +#define OP32 .byte 0x66 ; + +/* + * Procedure qui vide le buffer clavier. + */ +#define WAITKB \ + 1: ;\ + .word 0xeb ;\ + .word 0xeb ;\ + inb $0x64, %al ;\ + andb $0x2, %al ;\ + jnz 1b + + /* Le point d'entree dans le bootsect */ +.globl _bsect +_bsect: + + /* + * La portion qui suit est situee a un offset 0x7c00 en + * memoire. Attention donc aux references memoire dans cette + * partie. On choisit de rester en offset 0 (.org 0), mais on + * charge correctement les segments a 0x7c0. + */ + + movw $BOOT_SEG, %ax /* le bootsecteur est a 0x7C00 en lineaire */ + movw %ax, %ds /* on le copie a l'adresse COPY_ADRESS */ + xorw %si, %si /* comme cette adresse est la plus haute de la mem */ + xorw %di, %di /* on pourra charger un kernel + gros */ + movw $(BOOT_SIZE>>1), %cx + movw $COPY_SEG, %ax + movw %ax, %es + cld + rep ; movsw + + /* on continue a executer le bootsecteur, mais maintenant a + partir de 0x9F000, qu'on represente sous la forme + 0x9f00:offset */ + ljmp $COPY_SEG, $here + + /* + * A partir de maintenant, on est a un offset 0 en memoire + * (segment 0x9f00), conformement a ce que veut le compilo. + */ +here: + movw %ax, %ds + + /* Petite pile temporaire (1k - 3.84k en RAM ; les adresses 0-1k + correspondent au vecteur d'interruptions). */ + movw %ax, %ss + movw $(LOAD_ADRESS - 0x10), %sp + + /* Efface l'ecran */ + movb $0x0, %ah + movb $0x3, %al + int $0x10 + + /* Affiche les messages d'attente */ + movw $loadkern, %si + call message + movw $check, %si + call message + +check386: + /* + * la attention, plus complexe : on teste si le proc est un + * 386+ pour cela, on va essayer de modifier les bits 12 ? 14 + * du registre E-flag si la modification reste, alors le proc + * est un 386+, sinon, c'est =< 286 + * + * Merci a Emmanuel Marty pour la compatibilite avec les 386 + * "pre-jurassique" + */ + + pushf /* on sauvegarde le E-Flag */ + movb $0x70, %ah + pushw %ax + popf + pushf + popw %ax + orb %ah, %ah + je no386 /* si la modif n'est pas valable, alors on saute a + no386 */ + popf /* on les restaure ? la fin ... */ + + /* Message de confirmation de 386+ et d'attente */ + movw $found386, %si + call message + movw $loading, %si + call message + +/* Copie du noyau disquette => RAM a partir de 0x1000 + L'adresse de destination est définie par es:0, où es vaut + initialement 0x100 (ie correspond alors à l'adresse 256*16, soit 4 + ko). Chaque itération incrémente ce registre es de 32, ce qui + correspond à un bond de 32*16 en mémoire, soit la taille d'un + secteur. De cette façon, puisqu'on joue sur les segments plutôt que + sur les offsets, la taille du noyau n'est pas limitée à 64 ko. Elle + est limitée par contre à la taille de la mémoire disponible sous + les 1Mo, \ie 640 ko (0x9f000 - 0x1000). */ +copyKernel: + /* Chargement du noyau en LOAD_SEG:0 */ + /* 3 iterateurs : + - load_size : le nbre de secteurs a charger + - cl : le secteur ou on en est pour le + cylindre en cours (<= SECTS) + - dh : la tete en cours (0/1) + */ + movb $0, %dl + movw $LOAD_SEG, %ax + movw %ax, %es + + xorw %bx, %bx + xorw %dx, %dx + movw $1, %cx /* premier secteur */ + +.nextsector: /* prochain secteur */ + incb %cl /* en incrementant CL */ + cmpb $SECTS, %cl /* si CL =< SECTS (=nbre de secteurs/pistes) + alors on charge */ + jbe .sector + movb $1, %cl /* sinon on revient au secteur 1 */ + incb %dh /* mais sur l'autre tete */ + cmpb $1, %dh /* on recompare, si DH =< 1 */ + je .sector /* on charge */ + movb $0, %dh /* sinon on repasse a la tete 0 */ + incb %ch /* mais on change de cylindre */ + +.sector: + pushw %es + movw $0x0201, %ax /* service 0x2, chargement 0x1 seecteur */ + int $0x13 /* Go ! */ + jc halt /* erreur */ + popw %ax + addw $32, %ax /* on a charge un secteur, donc on doit + charger 512 bytes plus loin */ + movw %ax, %es /* on avance donc le segment du buffer de + 32bytes, ie 1 secteur en RAM (car 32*16=512) */ + + movw $(0x0E*256+'.'), %ax /* affiche un point */ + int $0x10 + + decw (load_size) /* et on repart pour le prochain secteur + tant qu'on n'a pas fini ! */ + jnz .nextsector + +after: + movw $0x03f2, %dx + inb %dx, %al /* stoppe le moteur */ + andb $0x0f, %al + outb %al, %dx + + cli /* on interdit les interruptions */ + +fincopie: + pushw %cs + popw %ds + + /* on ouvre la porte A20 */ + WAITKB /* on vide le buffer */ + movb $0xd1, %al /* on met a jour le port */ + outb %al, $0x64 + WAITKB + movb $0xdf, %al /* bit 2 = ouverture/fermeture */ + outb %al, $0x60 + + /* + * init gdt + */ +InitGDT: + /* Préparation du flat mode */ + lgdt gdtr + +GoPMode: + /* Passage en mode protégé */ + movl %cr0, %eax + orb $1, %al /* set PE bit to 1 */ + movl %eax, %cr0 + + /* we are not yet in Pmode jump 'in' pmode clearing prefetch + * queue and loading a new selector */ + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + +/* + * Code 32 bits ============================================================ + */ + .code32 + +JumpToHere32: /* Se deplace a l'endroit actuel, en passant en 32bits + et en utilisant la gdt, et vide la prefetch queue */ + .byte 0x66 /* Prefixe 32bits : en realite, jusqu'au jmp, on est + encore en 16 bits */ + ljmp $0x8, $(COPY_ADRESS+(Here32)) +Here32: + /* Et voila : On est en 32 bits vrai */ + +MoveKernelToFinalAddr: /* Deplace le noyau (en LOAD_ADDRESS) vers sa + destination finale (FINAL_ADDRESS) */ + movl $0x10, %eax + movl %eax, %ds /* Seg Src = DSeg */ + movl %eax, %es /* Sed Dest = DSeg */ + cld + movl $LOAD_ADRESS, %esi /* On commence la copie au debut du noyau */ + movl $FINAL_ADDRESS, %edi /* On copie vers cette adresse */ + movl $MAX_KERN_LEN, %ecx /* Taille recopie */ + shrl $2, %ecx + rep + movsl + +LaunchKernel: + /* Met en place une pile au niveau du symbole "stack" */ + movl %eax, %ss + movl $(stack + BOOT_STACK_SIZE), %ebp + movl %ebp, %esp + + /* Saut vers le noyau. La GDT est en place (flat mode), les + * selecteurs aussi, a20 est ouverte, et les interruptions sont + * cli + pas de idt. Le PIC n'est pas programme */ + ljmp $0x8, $sos_main + +/* + * Utilities ============================================================ + */ + .code16 + +message: + lodsb /* charge ds:si dans al et incremente si */ + orb %al, %al /* si al = 0 */ + jz 1f + movb $0x0e, %ah /* service 0Eh (affichage d'un caractere) */ + movw $0x0007, %bx /* Parametres : blanc sur fond noir */ + int $0x10 /* Appel de l'interruption 10h */ + jmp message /* On repart au début ... */ + 1: ret /* si la chaine est finie alors on retourne + dans la fonction appelante */ + +halt: + pushw %cs + popw %es + movw $haltmsg, %si + call message + cli + 1: jmp 1b + ret + +no386: + movw $need386, %si + call message + call halt + + /* + * GDT + */ + +gdt: +gdtr: +NULL_Desc: + .word (EndGDT)-(gdt)-1 /* Taille GDT */ + .long (gdt)+COPY_ADRESS +unused: + .word 0 + +CS_Desc: /* 0x8 */ + .word 0xFFFF, 0 + .byte 0, 0x9B, 0xCF, 0 + +DS_Desc: /* 0x10 */ + .word 0xFFFF, 0 + .byte 0, 0x93, 0xCF, 0 + +EndGDT: + + /* quelques messages */ + +loadkern: .string "-= S O S =- : The Simple Operating System \r\n" +check: .string "Checking for a 386+ processor... " +found386: .string " [OK]\r\n" +need386: .string " [FAILED]\r\n" +diskerror: .string "Disk Error\r\n" +loading: .string "Loading... " +haltmsg: .string "System Halted\r\n" + +/*** Les code/données du boot secteur se terminent ICI. le marqueur de + * fin (aa55) est ajouté automatiquement par le script ld + * sos_bsect.lds ***/ + +/* La pile de 16k qu'on utilise au niveau de LaunchKernel se trouve + declaree avec le noyau, dans sa section ".bss", cad HORS du boot + secteur ! (sinon ca depasserait 512B, forcément). On aurait pu la + définir directement dans le sos_bsect.lds, ou dans un fichier .c + auxiliaire pour plus de clarté */ +.comm stack, BOOT_STACK_SIZE diff --git a/sos-code-article3/extra/dot.mkvars b/sos-code-article3/extra/dot.mkvars new file mode 100644 index 0000000..1f7dca5 --- /dev/null +++ b/sos-code-article3/extra/dot.mkvars @@ -0,0 +1,29 @@ +# For cross-compilation and/or installations without grub available, +# copy this file as .mkvars to the root directory of the SOS sources, +# and customize the CC/LD/... variables. You still need the mtools +# installed and running + +CC := i586-gnu-gcc +LD := i586-gnu-ld +OBJCOPY := i586-gnu-objcopy +CFLAGS += -O3 + +# Configuration of mtools +MTOOLSRC = extra/mtoolsrc +export MTOOLSRC + +$(MULTIBOOT_IMAGE): $(KERNEL_OBJ) menu.txt + gzip -dc < extra/grub.img.gz > $@ + mcopy menu.txt v:/boot/grub/ + mmd v:/system + mcopy sos.elf v:/system/sos.elf + +menu.txt: + echo timeout 0 > $@ + echo default 0 >> $@ + echo title SOS >> $@ + echo "root (fd0)" >> $@ + echo kernel /system/sos.elf >> $@ + +runbochs: all + echo c | bochs -q diff --git a/sos-code-article3/extra/grub.img.gz b/sos-code-article3/extra/grub.img.gz Binary files differnew file mode 100644 index 0000000..4f98e74 --- /dev/null +++ b/sos-code-article3/extra/grub.img.gz diff --git a/sos-code-article3/extra/mtoolsrc b/sos-code-article3/extra/mtoolsrc new file mode 100644 index 0000000..df1a26e --- /dev/null +++ b/sos-code-article3/extra/mtoolsrc @@ -0,0 +1,2 @@ +# For older versions of mtools, you may have to remove "filter" +drive v: file="fd.img" 1.44M filter diff --git a/sos-code-article3/extra/qemu-port-e9.diff b/sos-code-article3/extra/qemu-port-e9.diff new file mode 100644 index 0000000..d8be044 --- /dev/null +++ b/sos-code-article3/extra/qemu-port-e9.diff @@ -0,0 +1,73 @@ +--- Makefile.target 17 Mar 2004 23:46:04 -0000 1.19 ++++ Makefile.target 18 Mar 2004 14:20:29 -0000 +@@ -217,7 +217,8 @@ + # must use static linking to avoid leaving stuff in virtual address space + VL_OBJS=vl.o osdep.o block.o monitor.o \ + ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ +- fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o ++ fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o \ ++ port-e9.o + ifeq ($(TARGET_ARCH), ppc) + VL_OBJS+= hw.o + endif +--- hw/pc.c 14 Mar 2004 21:46:48 -0000 1.2 ++++ hw/pc.c 18 Mar 2004 14:20:29 -0000 +@@ -371,6 +371,7 @@ + SB16_init(); + + fdctrl_init(6, 2, 0, 0x3f0, fd_table); ++ port_e9_init(); + + cmos_init(ram_size, boot_device); + } +--- /dev/null 2003-01-30 11:24:37.000000000 +0100 ++++ port-e9.c 2004-03-18 15:18:52.660493187 +0100 +@@ -0,0 +1,38 @@ ++/* ++ * QEMU Port 0xe9 hack ++ * ++ * Copyright (c) 2000-2004 E. Marty, the bochs team, D. Decotigny ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++#include <stdio.h> ++#include <unistd.h> ++#include <inttypes.h> ++ ++#include "vl.h" ++ ++static void bochs_e9_write(void *opaque, uint32_t address, uint32_t data) ++{ ++ write(fileno(stdout), &data, 1); ++} ++ ++void port_e9_init () ++{ ++ register_ioport_write(0xe9, 1, 1, bochs_e9_write, NULL); ++} +--- vl.h 17 Mar 2004 23:17:16 -0000 1.14 ++++ vl.h 18 Mar 2004 14:29:06 -0000 +@@ -268,4 +268,7 @@ + void term_flush(void); + void term_print_help(void); + ++/* port-e9.c */ ++void port_e9_init(void); ++ + #endif /* VL_H */ diff --git a/sos-code-article3/extra/sos_bsect.lds b/sos-code-article3/extra/sos_bsect.lds new file mode 100644 index 0000000..ac42f23 --- /dev/null +++ b/sos-code-article3/extra/sos_bsect.lds @@ -0,0 +1,61 @@ +/* Copyright (C) 2004, David Decotigny + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +SECTIONS +{ + /* *********************************************** + * The bootsector is here. We link it against the remaining of the kernel + * in order to automatically figure out its size that must be loaded + * from file to memory (see the load_size definition below) + */ + + /* If we use one, we put the boot sector here. We don't set its + * address to 0x7c000 (aka 0x7c00:0), since it reloads itself to + * 0x9f000, causing the 0x7c000 address to be meaningless too. So we + * chose to pretend that the address is 0x0, and to make a little + * address arithmetic in bootsect.S */ + .bootsect 0x0 : + { + /* The code for the boot sector goes here */ + *(.bootsect); + + /* The load_size symbol contains the size of the area (in + * sectors, aka 512 Bytes) that the boot sector should copy from + * the disk. The bss section is not included since it uses 0 + * bytes on disk */ + load_size = .; + LONG((__e_load - __b_load + 511) >> 9); + /* ---> This is equivalent to ceil( (__e_load - __b_load) / 512 ) */ + + /* At offsets 511 and 512, we set the boot sector signature (AA55h) */ + . = 0x1fe; + SHORT(0xAA55); + } +} + + +/* This is to avoid a cut/paste here. Please notice that a multiboot + * section WILL be inserted, which is NOT mandatory (we could have + * removed it without getting into trouble). Please note however that + * the *.bin files will NOT be multiboot compatible (they are not in ELF + * format): they are expected to be directly booted by the BIOS (or + * by the "chainloader" command of Grub). */ +INCLUDE ../support/sos.lds + +/* We overload the entry set in sos.lds, just to avoid an ld warning */ +ENTRY(sos_main); diff --git a/sos-code-article3/hwcore/exception.c b/sos-code-article3/hwcore/exception.c new file mode 100644 index 0000000..9ab5aff --- /dev/null +++ b/sos-code-article3/hwcore/exception.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "idt.h" +#include "irq.h" + +#include "exception.h" + +/* array of exception wrappers, defined in exception_wrappers.S */ +extern sos_vaddr_t sos_exception_wrapper_array[SOS_EXCEPT_NUM]; + +/* arrays of exception handlers, shared with exception_wrappers.S */ +sos_exception_handler_t sos_exception_handler_array[SOS_EXCEPT_NUM] = + { NULL, }; + +sos_ret_t sos_exceptions_setup(void) +{ + /* We inidicate that the double fault exception handler is defined, + and give its address. this handler is a do-nothing handler (see + exception_wrappers.S), and it can NOT be overriden by the + functions below */ + return sos_idt_set_handler(SOS_EXCEPT_BASE + SOS_EXCEPT_DOUBLE_FAULT, + (sos_vaddr_t) sos_exception_wrapper_array[SOS_EXCEPT_DOUBLE_FAULT], + 0 /* CPL0 routine */); +} + + +sos_ret_t sos_exception_set_routine(int exception_number, + sos_exception_handler_t routine) +{ + sos_ret_t retval; + sos_ui32_t flags; + + if ((exception_number < 0) || (exception_number >= SOS_EXCEPT_NUM)) + return -SOS_EINVAL; + + /* Double fault not supported */ + if (exception_number == SOS_EXCEPT_DOUBLE_FAULT) + return -SOS_ENOSUP; + + sos_disable_IRQs(flags); + + retval = SOS_OK; + + /* Set the exception routine to be called by the exception wrapper */ + sos_exception_handler_array[exception_number] = routine; + + /* If the exception is to be enabled, update the IDT with the exception + wrapper */ + if (routine != NULL) + retval + = sos_idt_set_handler(SOS_EXCEPT_BASE + exception_number, + (sos_vaddr_t) sos_exception_wrapper_array[exception_number], + 0 /* CPL0 routine */); + else /* Disable the IDT entry */ + retval + = sos_idt_set_handler(SOS_EXCEPT_BASE + exception_number, + (sos_vaddr_t)NULL /* No routine => disable IDTE */, + 0 /* don't care */); + + sos_restore_IRQs(flags); + return retval; +} + + +sos_exception_handler_t sos_exception_get_routine(int exception_number) +{ + if ((exception_number < 0) || (exception_number >= SOS_EXCEPT_NUM)) + return NULL; + + /* Double fault not supported */ + if (exception_number == SOS_EXCEPT_DOUBLE_FAULT) + return NULL; + + /* Expected to be atomic */ + return sos_exception_handler_array[exception_number]; +} diff --git a/sos-code-article3/hwcore/exception.h b/sos-code-article3/hwcore/exception.h new file mode 100644 index 0000000..7e52fe5 --- /dev/null +++ b/sos-code-article3/hwcore/exception.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_HWEXCEPT_H_ +#define _SOS_HWEXCEPT_H_ + +/** + * @file exception.c + * + * Hardware exception routines management. + */ + +#ifndef ASM_SOURCE +# include <sos/errno.h> +#endif + +/** + * Standard Intel x86 exceptions. + * + * @see Intel x86 doc vol 3, section 5.12. + */ +#define SOS_EXCEPT_DIVIDE_ERROR 0 // No error code +#define SOS_EXCEPT_DEBUG 1 // No error code +#define SOS_EXCEPT_NMI_INTERRUPT 2 // No error code +#define SOS_EXCEPT_BREAKPOINT 3 // No error code +#define SOS_EXCEPT_OVERFLOW 4 // No error code +#define SOS_EXCEPT_BOUND_RANGE_EXCEDEED 5 // No error code +#define SOS_EXCEPT_INVALID_OPCODE 6 // No error code +#define SOS_EXCEPT_DEVICE_NOT_AVAILABLE 7 // No error code +#define SOS_EXCEPT_DOUBLE_FAULT 8 // Yes (Zero) +#define SOS_EXCEPT_COPROCESSOR_SEGMENT_OVERRUN 9 // No error code +#define SOS_EXCEPT_INVALID_TSS 10 // Yes +#define SOS_EXCEPT_SEGMENT_NOT_PRESENT 11 // Yes +#define SOS_EXCEPT_STACK_SEGMENT_FAULT 12 // Yes +#define SOS_EXCEPT_GENERAL_PROTECTION 13 // Yes +#define SOS_EXCEPT_PAGE_FAULT 14 // Yes +#define SOS_EXCEPT_INTEL_RESERVED_1 15 // No +#define SOS_EXCEPT_FLOATING_POINT_ERROR 16 // No +#define SOS_EXCEPT_ALIGNEMENT_CHECK 17 // Yes (Zero) +#define SOS_EXCEPT_MACHINE_CHECK 18 // No +#define SOS_EXCEPT_INTEL_RESERVED_2 19 // No +#define SOS_EXCEPT_INTEL_RESERVED_3 20 // No +#define SOS_EXCEPT_INTEL_RESERVED_4 21 // No +#define SOS_EXCEPT_INTEL_RESERVED_5 22 // No +#define SOS_EXCEPT_INTEL_RESERVED_6 23 // No +#define SOS_EXCEPT_INTEL_RESERVED_7 24 // No +#define SOS_EXCEPT_INTEL_RESERVED_8 25 // No +#define SOS_EXCEPT_INTEL_RESERVED_9 26 // No +#define SOS_EXCEPT_INTEL_RESERVED_10 27 // No +#define SOS_EXCEPT_INTEL_RESERVED_11 28 // No +#define SOS_EXCEPT_INTEL_RESERVED_12 29 // No +#define SOS_EXCEPT_INTEL_RESERVED_13 30 // No +#define SOS_EXCEPT_INTEL_RESERVED_14 31 // No + +#ifndef ASM_SOURCE + +typedef void (*sos_exception_handler_t)(int exception_number); + +sos_ret_t sos_exceptions_setup(void); +sos_ret_t sos_exception_set_routine(int exception_number, + sos_exception_handler_t routine); +sos_exception_handler_t sos_exception_get_routine(int exception_number); +#endif /* ! ASM_SOURCE */ + +#endif /* _SOS_HWEXCEPT_H_ */ diff --git a/sos-code-article3/hwcore/exception_wrappers.S b/sos-code-article3/hwcore/exception_wrappers.S new file mode 100644 index 0000000..2f7665c --- /dev/null +++ b/sos-code-article3/hwcore/exception_wrappers.S @@ -0,0 +1,197 @@ +/* Copyright (C) 2004 The KOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "exception.h" + +.file "exception_wrappers.S" + +.text + +/* The address of the table of handlers (defined in exception.c) */ +.extern sos_exception_handler_array + +/* The address of the table of wrappers (defined below, and shared + with exception.c */ +.globl sos_exception_wrapper_array + + +/** + * For exceptions with/without error code, refer to Intel x86 doc vol 3, + * section 5.12 + */ + +/* These wrappers are for exceptions without error code */ +.irp id, \ + SOS_EXCEPT_DIVIDE_ERROR, \ + SOS_EXCEPT_DEBUG, \ + SOS_EXCEPT_NMI_INTERRUPT, \ + SOS_EXCEPT_BREAKPOINT, \ + SOS_EXCEPT_OVERFLOW, \ + SOS_EXCEPT_BOUND_RANGE_EXCEDEED, \ + SOS_EXCEPT_INVALID_OPCODE, \ + SOS_EXCEPT_DEVICE_NOT_AVAILABLE, \ + SOS_EXCEPT_COPROCESSOR_SEGMENT_OVERRUN, \ + SOS_EXCEPT_INTEL_RESERVED_1, \ + SOS_EXCEPT_FLOATING_POINT_ERROR, \ + SOS_EXCEPT_MACHINE_CHECK, \ + SOS_EXCEPT_INTEL_RESERVED_2, \ + SOS_EXCEPT_INTEL_RESERVED_3, \ + SOS_EXCEPT_INTEL_RESERVED_4, \ + SOS_EXCEPT_INTEL_RESERVED_5, \ + SOS_EXCEPT_INTEL_RESERVED_6, \ + SOS_EXCEPT_INTEL_RESERVED_7, \ + SOS_EXCEPT_INTEL_RESERVED_8, \ + SOS_EXCEPT_INTEL_RESERVED_9, \ + SOS_EXCEPT_INTEL_RESERVED_10, \ + SOS_EXCEPT_INTEL_RESERVED_11, \ + SOS_EXCEPT_INTEL_RESERVED_12, \ + SOS_EXCEPT_INTEL_RESERVED_13, \ + SOS_EXCEPT_INTEL_RESERVED_14 + + .p2align 2, 0x90 + sos_exception_wrapper_\id: + .type sos_exception_wrapper_\id,@function + + /* Fake error code */ + pushl $0 + /* Backup the context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Call the handler with exception number as + * argument */ + pushl $\id + leal sos_exception_handler_array,%edi + call *\id*4(%edi) + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + + popl %ebp + /* Remove fake error code */ + addl $4, %esp + iret +.endr + + /* These wrappers are for exceptions with error code */ +.irp id, \ + SOS_EXCEPT_INVALID_TSS, \ + SOS_EXCEPT_SEGMENT_NOT_PRESENT, \ + SOS_EXCEPT_STACK_SEGMENT_FAULT, \ + SOS_EXCEPT_GENERAL_PROTECTION, \ + SOS_EXCEPT_PAGE_FAULT, \ + SOS_EXCEPT_ALIGNEMENT_CHECK + + .p2align 2, 0x90 + sos_exception_wrapper_\id: + .type sos_exception_wrapper_\id,@function + + /* ret eflags */ + /* ret cs */ + /* ret eip */ + /* Error code */ + + /* Backup the context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Call the handler with exception number as + * argument */ + pushl $\id + leal sos_exception_handler_array,%edi + call *\id*4(%edi) + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + + /* Error code isn't compatible with iretd */ + addl $4, %esp + + iret +.endr + + +/* Double fault handler not supported. We must define it since we + define an entry for it in the sos_exception_wrapper_array. */ +.irp id, SOS_EXCEPT_DOUBLE_FAULT +.p2align 2, 0x90 +sos_exception_wrapper_\id: +.type sos_exception_wrapper_\id,@function +1: hlt + jmp 1b /* Machine halting */ +.endr + +/* Build the sos_irq_wrapper_array, shared with interrupt.c */ +.section ".rodata" +.p2align 5, 0x0 +sos_exception_wrapper_array: + .irp id, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, \ + 16,17,18,19,20,21,22,23,24,25,26,27,29,30,31 + .long (sos_exception_wrapper_\id) + .endr diff --git a/sos-code-article3/hwcore/gdt.c b/sos-code-article3/hwcore/gdt.c new file mode 100644 index 0000000..7945c8c --- /dev/null +++ b/sos-code-article3/hwcore/gdt.c @@ -0,0 +1,150 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "segment.h" + +#include "gdt.h" + + +/** + * The sructure of a segment descriptor. + * + * @see Intel x86 doc, Vol 3, section 3.4.3, figure 3-8. For segment + * types, see section 3.5 + */ +struct x86_segment_descriptor +{ + /* Lowest dword */ + sos_ui16_t limit_15_0; /* Segment limit, bits 15..0 */ + sos_ui16_t base_paged_addr_15_0; /* Base address, bits 15..0 */ + + /* Highest dword */ + sos_ui8_t base_paged_addr_23_16; /* Base address bits 23..16 */ + sos_ui8_t segment_type:4; /* Section 3.4.3.1 (code/data) + and 3.5 (system) of Intel x86 vol 3 */ + sos_ui8_t descriptor_type:1; /* 0=system, 1=Code/Data */ + sos_ui8_t dpl:2; + sos_ui8_t present:1; + + sos_ui8_t limit_19_16:4; /* Segment limit, bits 19..16 */ + sos_ui8_t custom:1; + sos_ui8_t zero:1; + sos_ui8_t op_size:1; /* 0=16bits instructions, 1=32bits */ + sos_ui8_t granularity:1; /* 0=limit in bytes, 1=limit in pages */ + + sos_ui8_t base_paged_addr_31_24; /* Base address bits 31..24 */ +} __attribute__ ((packed, aligned (8))); + + +/** + * The GDT register, which stores the address and size of the + * GDT. + * + * @see Intel x86 doc vol 3, section 2.4, figure 2-4; and section + * 3.5.1 + */ +struct x86_gdt_register { + /* The maximum GDT offset allowed to access an entry in the GDT */ + sos_ui16_t limit; + + /* This is not exactly a "virtual" address, ie an adddress such as + those of instructions and data; this is a "linear" address, ie an + address in the paged memory. However, in SOS we configure the + segmented memory as a "flat" space: the 0-4GB segment-based (ie + "virtual") addresses directly map to the 0-4GB paged memory (ie + "linear"), so that the "linear" addresses are numerically equal + to the "virtual" addresses: this base_addr will thus be the same + as the address of the gdt array */ + sos_ui32_t base_addr; +} __attribute__((packed, aligned(8))); + + +/** + * Helper macro that builds a Segment descriptor for the virtual + * 0..4GB addresses to be mapped to the linear 0..4GB linear + * addresses. + */ +#define BUILD_GDTE(descr_privilege_level,is_code) \ + ((struct x86_segment_descriptor) { \ + .limit_15_0= 0xffff, \ + .base_paged_addr_15_0= 0, \ + .base_paged_addr_23_16= 0, \ + .segment_type= ((is_code)?0xb:0x3), \ + /* With descriptor_type (below) = 1 (code/data), \ + * see Figure 3-1 of section 3.4.3.1 in Intel \ + * x86 vol 3: \ + * - Code (bit 3 = 1): \ + * bit 0: 1=Accessed \ + * bit 1: 1=Readable \ + * bit 2: 0=Non-Conforming \ + * - Data (bit 3 = 0): \ + * bit 0: 1=Accessed \ + * bit 1: 1=Writable \ + * bit 2: 0=Expand up (stack-related) \ + * For Conforming/non conforming segments, see \ + * Intel x86 Vol 3 section 4.8.1.1 \ + */ \ + .descriptor_type= 1, /* 1=Code/Data */ \ + .dpl= ((descr_privilege_level) & 0x3), \ + .present= 1, \ + .limit_19_16= 0xf, \ + .custom= 0, \ + .op_size= 1, /* 32 bits instr/data */ \ + .granularity= 1 /* limit is in 4kB Pages */ \ + }) + + +/** The actual GDT */ +static struct x86_segment_descriptor gdt[] = { + [SOS_SEG_NULL] = (struct x86_segment_descriptor){ 0, }, + [SOS_SEG_KCODE] = BUILD_GDTE(0, 1), + [SOS_SEG_KDATA] = BUILD_GDTE(0, 0), +}; + +sos_ret_t sos_gdt_setup(void) +{ + struct x86_gdt_register gdtr; + + /* Address of the GDT */ + gdtr.base_addr = (sos_ui32_t) gdt; + + /* The limit is the maximum offset in bytes from the base address of + the GDT */ + gdtr.limit = sizeof(gdt) - 1; + + /* Commit the GDT into the CPU, and update the segment + registers. The CS register may only be updated with a long jump + to an absolute address in the given segment (see Intel x86 doc + vol 3, section 4.8.1). */ + asm volatile ("lgdt %0 \n\ + ljmp %1,$1f \n\ + 1: \n\ + movw %2, %%ax \n\ + movw %%ax, %%ss \n\ + movw %%ax, %%ds \n\ + movw %%ax, %%es \n\ + movw %%ax, %%fs \n\ + movw %%ax, %%gs" + : + :"m"(gdtr), + "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE)), + "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA)) + :"memory","eax"); + + return SOS_OK; +} diff --git a/sos-code-article3/hwcore/gdt.h b/sos-code-article3/hwcore/gdt.h new file mode 100644 index 0000000..b7e3f4c --- /dev/null +++ b/sos-code-article3/hwcore/gdt.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_GDT_H_ +#define _SOS_GDT_H_ + +/** + * @file gdt.h + * + * The routines that manage the GDT, the table that maps the virtual + * addresses (data/instructions, segment-relative), to "linear" + * addresses (ie paged-memory). In SOS/x86, we use a "flat" virtual + * space, ie the virtual and linear spaces are equivalent. + * + * @see Intel x86 doc vol 3, chapter 3 + */ + +#include <sos/errno.h> + +/** + * Configure the virtual space as a direct mapping to the linear + * address space (ie "flat" virtual space). + */ +sos_ret_t sos_gdt_setup(void); + +#endif /* _SOS_GDT_H_ */ diff --git a/sos-code-article3/hwcore/i8254.c b/sos-code-article3/hwcore/i8254.c new file mode 100644 index 0000000..5fbb156 --- /dev/null +++ b/sos-code-article3/hwcore/i8254.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2004 The KOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <hwcore/ioports.h> + +#include "i8254.h" + +/** 82c54 clock frequency */ +#define I8254_MAX_FREQ 1193180 + +/* Ports to communicate with the 82c54 */ +#define I8254_TIMER0 0x40 +#define I8254_TIMER1 0x41 +#define I8254_TIMER2 0x42 +#define I8254_CONTROL 0x43 + +/** + * Configure the first timer of the 82c54 chip as a rate generator, + * which will raise an IRQ0 on a regular periodic basis, as given by + * the freq parameter. Second (RAM refresh) and third (speaker) timers + * are left unchanged. Maximum frequency is that of the 8254 clock, ie + * 1193180 Hz. + * + * Ahhh PC systems are nice toys: this maximum "strange" frequency + * equals that of the NTSC clock (14.31818 MHz) divided by 12. In + * turn, the famous 4.77 MHz cpu clock frequency of the first IBM PC + * is this same NTSC frequency divided by 3. Why the NTSC frequency as + * a base "standard" ? Because the 14.31818 MHz quartz were cheap at + * that time, and because it allows to simply drive altogether the + * cpu, the "time of day" timer, and the video signal generators. + */ +sos_ret_t sos_i8254_set_frequency(unsigned int freq) +{ + unsigned int nb_tick; + + if (freq <= 0) + return -SOS_EINVAL; + + /* Compute counter value */ + nb_tick = I8254_MAX_FREQ / freq; + + /* Counter must be between 1 and 65536 */ + if (nb_tick > 65536) + return -SOS_EINVAL; + if (nb_tick <= 0) + return -SOS_EINVAL; + + /* The i8254 interprets 0 to mean counter == 65536, because 65536 + cannot be coded on 16bits */ + if (nb_tick == 65536) + nb_tick = 0; + + /* We want to configure timer0, we want to send both LSB+MSB to set + timer0 freq (-> 0x30), and we configure timer0 in mode 2, ie as a + rate generator (-> 0x4) ==> 0x34 */ + outb(0x34, I8254_CONTROL); + + /* Send LSB of counter first */ + outb((nb_tick & 0xFF), I8254_TIMER0); + + /* Send MSB of counter */ + outb((nb_tick >> 8) & 0xFF, I8254_TIMER0); + + return SOS_OK; +} diff --git a/sos-code-article3/hwcore/i8254.h b/sos-code-article3/hwcore/i8254.h new file mode 100644 index 0000000..4838ff4 --- /dev/null +++ b/sos-code-article3/hwcore/i8254.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_i8259_H_ +#define _SOS_i8259_H_ + +#include <sos/errno.h> + +/** + * @file i8254.h PC programmable timer + * + * Programmable timer routines. See the Intel 82C54 datasheet (on kos + * website). + * + * @see i82C54 datasheet on Kos website. + */ + +/** Change timer interrupt (IRQ 0) frequency */ +sos_ret_t sos_i8254_set_frequency(unsigned int freq); + +#endif /* _SOS_i8259_H_ */ diff --git a/sos-code-article3/hwcore/i8259.c b/sos-code-article3/hwcore/i8259.c new file mode 100644 index 0000000..8391c07 --- /dev/null +++ b/sos-code-article3/hwcore/i8259.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2004 The KOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "ioports.h" + +#include "i8259.h" + +#define PIC_MASTER 0x20 +#define PIC_SLAVE 0xa0 + +/** Setup the 8259 PIC */ +sos_ret_t sos_i8259_setup(void) +{ + /* Send ICW1: 8086 mode + NOT Single ctrl + call address + interval=8 */ + outb(0x11, PIC_MASTER); + outb(0x11, PIC_SLAVE); + + /* Send ICW2: ctrl base address */ + outb(0x20, PIC_MASTER+1); + outb(0x28, PIC_SLAVE+1); + + /* Send ICW3 master: mask where slaves are connected */ + outb(0x4, PIC_MASTER+1); + /* Send ICW3 slave: index where the slave is connected on master */ + outb(0x2, PIC_SLAVE+1); + + /* Send ICW4: 8086 mode, fully nested, not buffered, no implicit EOI */ + outb(0x1, PIC_MASTER+1); + outb(0x1, PIC_SLAVE+1); + + /* Send OCW1: + * Closing all IRQs : waiting for a correct handler The only IRQ + * enabled is the cascade (that's why we use 0xFB for the master) */ + outb(0xFB, PIC_MASTER+1); + outb(0xFF, PIC_SLAVE+1); + + return SOS_OK; +} + + +sos_ret_t sos_i8259_enable_irq_line(int numirq) +{ + if(numirq < 8) + /* irq on master PIC */ + outb((inb(PIC_MASTER+1) & ~(1 << numirq)), PIC_MASTER+1); + else + /* irq on slave PIC */ + outb((inb(PIC_SLAVE+1) & ~(1 << (numirq-8))), PIC_SLAVE+1); + + return SOS_OK; +} + + +sos_ret_t sos_i8259_disable_irq_line(int numirq) +{ + if(numirq < 8) + /* irq on master PIC */ + outb((inb(PIC_MASTER+1) | (1 << numirq)), PIC_MASTER+1); + else + /* irq on slave PIC */ + outb((inb(PIC_SLAVE+1) | (1 << (numirq-8))), PIC_SLAVE+1); + + return SOS_OK; +} diff --git a/sos-code-article3/hwcore/i8259.h b/sos-code-article3/hwcore/i8259.h new file mode 100644 index 0000000..c1771dd --- /dev/null +++ b/sos-code-article3/hwcore/i8259.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_i8259_H_ +#define _SOS_i8259_H_ + +#include <sos/errno.h> + +/** + * @file i8259.h PIC + * + * PIC Management routines. See the Intel 8259A datasheet (on kos + * website), page 9+. Should be not be used directly: only interrupt.c + * should use this. + * + * @see i8259A datasheet on Kos website. + */ + +/** Setup PIC and Disable all IRQ lines */ +sos_ret_t sos_i8259_setup(void); + +sos_ret_t sos_i8259_enable_irq_line(int numirq); + +sos_ret_t sos_i8259_disable_irq_line(int numirq); + +#endif /* _SOS_i8259_H_ */ diff --git a/sos-code-article3/hwcore/idt.c b/sos-code-article3/hwcore/idt.c new file mode 100644 index 0000000..51e3a9d --- /dev/null +++ b/sos-code-article3/hwcore/idt.c @@ -0,0 +1,160 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "segment.h" + +#include "idt.h" + +/** + * An entry in the IDT, or "IDTE" in the following, ie a reference to + * a interrupt/trap routine or a task gate to handle the sw/hw + * interrupts and exceptions. + * + * @see figure 5-2, intel x86 doc, vol 3 + */ +struct x86_idt_entry +{ + /* Low dword */ + sos_ui16_t offset_low; /* 15..0, offset of the routine in the segment */ + sos_ui16_t seg_sel; /* 31..16, the ID of the segment */ + + /* High dword */ + sos_ui8_t reserved:5; /* 4..0 */ + sos_ui8_t flags:3; /* 7..5 */ + sos_ui8_t type:3; /* 10..8 (interrupt gate, trap gate...) */ + sos_ui8_t op_size:1; /* 11 (0=16bits instructions, 1=32bits instr.) */ + sos_ui8_t zero:1; /* 12 */ + sos_ui8_t dpl:2; /* 14..13 */ + sos_ui8_t present:1; /* 15 */ + sos_ui16_t offset_high; /* 31..16 */ +} __attribute__((packed)); + + +/** + * The IDT register, which stores the address and size of the + * IDT. + * + * @see Intel x86 doc vol 3, section 2.4, figure 2-4 + */ +struct x86_idt_register +{ + /* The maximum GDT offset allowed to access an entry in the GDT */ + sos_ui16_t limit; + + /* This is not exactly a "virtual" address, ie an adddress such as + those of instructions and data; this is a "linear" address, ie an + address in the paged memory. However, in SOS we configure the + segmented memory as a "flat" space: the 0-4GB segment-based (ie + "virtual") addresses directly map to the 0-4GB paged memory (ie + "linear"), so that the "linear" addresses are numerically equal + to the "virtual" addresses: this base_addr will thus be the same + as the address of the gdt array */ + sos_ui32_t base_addr; +} __attribute__((packed, aligned (8))); + + +static struct x86_idt_entry idt[SOS_IDTE_NUM]; + +sos_ret_t sos_idt_setup() +{ + struct x86_idt_register idtr; + int i; + + for (i = 0 ; + i < SOS_IDTE_NUM ; + i++) + { + struct x86_idt_entry *idte = idt + i; + + /* Setup an empty IDTE interrupt gate, see figure 5-2 in Intel + x86 doc, vol 3 */ + idte->seg_sel = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE); + idte->reserved = 0; + idte->flags = 0; + idte->type = 0x6; /* Interrupt gate (110b) */ + idte->op_size = 1; /* 32bits instructions */ + idte->zero = 0; + + /* Disable this IDT entry for the moment */ + sos_idt_set_handler(i, (sos_vaddr_t)NULL, 0/* Don't care */); + } + + /* + * Setup the IDT register, see Intel x86 doc vol 3, section 5.8. + */ + + /* Address of the IDT */ + idtr.base_addr = (sos_ui32_t) idt; + + /* The limit is the maximum offset in bytes from the base address of + the IDT */ + idtr.limit = sizeof(idt) - 1; + + /* Commit the IDT into the CPU */ + asm volatile ("lidt %0\n"::"m"(idtr):"memory"); + + return SOS_OK; +} + + +sos_ret_t sos_idt_set_handler(int index, + sos_vaddr_t handler_address, + int lowest_priviledge /* 0..3 */) +{ + struct x86_idt_entry *idte; + + if ((index < 0) || (index >= SOS_IDTE_NUM)) + return -SOS_EINVAL; + if ((lowest_priviledge < 0) || (lowest_priviledge > 3)) + return -SOS_EINVAL; + + idte = idt + index; + if (handler_address != (sos_vaddr_t)NULL) + { + idte->offset_low = handler_address & 0xffff; + idte->offset_high = (handler_address >> 16) & 0xffff; + idte->dpl = lowest_priviledge; + idte->present = 1; /* Yes, there is a handler */ + } + else /* Disable this IDT entry */ + { + idte->offset_low = 0; + idte->offset_high = 0; + idte->dpl = 0; + idte->present = 0; /* No, there is no handler */ + } + + return SOS_OK; +} + + +sos_ret_t sos_idt_get_handler(int index, + sos_vaddr_t *handler_address, + int *lowest_priviledge) +{ + if ((index < 0) || (index >= SOS_IDTE_NUM)) + return -SOS_EINVAL; + + if (handler_address != NULL) + *handler_address = idt[index].offset_low + | (idt[index].offset_high << 16); + if (lowest_priviledge != NULL) + *lowest_priviledge = idt[index].dpl; + + return SOS_OK; +} diff --git a/sos-code-article3/hwcore/idt.h b/sos-code-article3/hwcore/idt.h new file mode 100644 index 0000000..7afe364 --- /dev/null +++ b/sos-code-article3/hwcore/idt.h @@ -0,0 +1,85 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_IDT_H_ +#define _SOS_IDT_H_ + +/** + * @file idt.h + * + * Manage the x86 Interrupt Descriptor Table, the table which maps the + * hardware interrupt lines, hardware exceptions, and software + * interrupts, to software routines. We only define "interrupt gate" + * IDT entries. Don't use it directly; refer instead to interrupt.c, + * exceptions.c and syscall.c. + * + * @see Intel x86 doc, Vol 3, chapter 5 + */ + +#include <sos/errno.h> +#include <sos/types.h> + +/* Mapping of the CPU exceptions in the IDT (imposed by Intel + standards) */ +#define SOS_EXCEPT_BASE 0 +#define SOS_EXCEPT_NUM 32 +#define SOS_EXCEPT_MAX (SOS_HWEXCEPT_BASE + SOS_HWEXCEPT_NUM - 1) + +/* Mapping of the IRQ lines in the IDT */ +#define SOS_IRQ_BASE 32 +#define SOS_IRQ_NUM 16 +#define SOS_IRQ_MAX (SOS_IRQ_BASE + SOS_IRQ_NUM - 1) + +/** + * Number of IDT entries. + * + * @note Must be large enough to map the hw interrupts, the exceptions + * (=> total is 48 entries), and the syscall(s). Since our syscall + * will be 0x42, it must be >= 0x43. Intel doc limits this to 256 + * entries, we use this limit. + */ +#define SOS_IDTE_NUM 256 /* 0x100 */ + +/** Initialization routine: all the IDT entries (or "IDTE") are marked + "not present". */ +sos_ret_t sos_idt_setup(void); + +/** + * Enable the IDT entry if handler_address != NULL, with the given + * lowest_priviledge.\ Disable the IDT entry when handler_address == + * NULL (the lowest_priviledge parameter is then ignored). Intel doc + * says that there must not be more than 256 entries. + * + * @note IRQ Unsafe + */ +sos_ret_t sos_idt_set_handler(int index, + sos_vaddr_t handler_address, + int lowest_priviledge /* 0..3 */); + + +/** + * @note IRQ Unsafe + * + * @return the handler address and DPL in the 2nd and 3rd + * parameters + */ +sos_ret_t sos_idt_get_handler(int index, + sos_vaddr_t *handler_address, + int *lowest_priviledge); + +#endif /* _SOS_IDT_H_ */ diff --git a/sos-code-article3/hwcore/ioports.h b/sos-code-article3/hwcore/ioports.h new file mode 100644 index 0000000..443acb7 --- /dev/null +++ b/sos-code-article3/hwcore/ioports.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2004 All GPL'ed OS + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_IOPORTS_H_ +#define _SOS_IOPORTS_H_ + +/** + * @ioports.h + * + * Intel-specific I/O space access routines. + */ + +/* This macro allows to write to an I/O port */ +#define outb(value, port) \ + __asm__ volatile ( \ + "outb %b0,%w1" \ + ::"a" (value),"Nd" (port) \ + ) \ + +// read one byte from port +#define inb(port) \ +({ \ + unsigned char _v; \ + __asm__ volatile ( \ + "inb %w1,%0" \ + :"=a" (_v) \ + :"Nd" (port) \ + ); \ + _v; \ +}) + +#endif /* _SOS_IOPORTS_H_ */ diff --git a/sos-code-article3/hwcore/irq.c b/sos-code-article3/hwcore/irq.c new file mode 100644 index 0000000..6ec3371 --- /dev/null +++ b/sos-code-article3/hwcore/irq.c @@ -0,0 +1,91 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "idt.h" +#include "i8259.h" + +#include "irq.h" + +/* array of IRQ wrappers, defined in irq_wrappers.S */ +extern sos_vaddr_t sos_irq_wrapper_array[SOS_IRQ_NUM]; + +/* arrays of IRQ handlers, shared with irq_wrappers.S */ +sos_irq_handler_t sos_irq_handler_array[SOS_IRQ_NUM] = { NULL, }; + + +sos_ret_t sos_irq_setup(void) +{ + return sos_i8259_setup(); +} + + +sos_ret_t sos_irq_set_routine(int irq_level, + sos_irq_handler_t routine) +{ + sos_ret_t retval; + sos_ui32_t flags; + + if ((irq_level < 0) || (irq_level >= SOS_IRQ_NUM)) + return -SOS_EINVAL; + + sos_disable_IRQs(flags); + + retval = SOS_OK; + + /* Set the irq routine to be called by the IRQ wrapper */ + sos_irq_handler_array[irq_level] = routine; + + /* If the irq is to be enabled, update the IDT with the IRQ + wrapper */ + if (routine != NULL) + { + retval + = sos_idt_set_handler(SOS_IRQ_BASE + irq_level, + (sos_vaddr_t) sos_irq_wrapper_array[irq_level], + 0 /* CPL0 routine */); + /* A problem occured */ + if (retval != SOS_OK) + sos_irq_handler_array[irq_level] = NULL; + } + else /* Disable this idt entry */ + { + retval + = sos_idt_set_handler(SOS_IRQ_BASE + irq_level, + (sos_vaddr_t)NULL /* Disable IDTE */, + 0 /* Don't care */); + } + + /* Update the PIC only if an IRQ handler has been set */ + if (sos_irq_handler_array[irq_level] != NULL) + sos_i8259_enable_irq_line(irq_level); + else + sos_i8259_disable_irq_line(irq_level); + + sos_restore_IRQs(flags); + return retval; +} + + +sos_irq_handler_t sos_irq_get_routine(int irq_level) +{ + if ((irq_level < 0) || (irq_level >= SOS_IRQ_NUM)) + return NULL; + + /* Expected to be atomic */ + return sos_irq_handler_array[irq_level]; +} diff --git a/sos-code-article3/hwcore/irq.h b/sos-code-article3/hwcore/irq.h new file mode 100644 index 0000000..5b39230 --- /dev/null +++ b/sos-code-article3/hwcore/irq.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_HWINTR_H_ +#define _SOS_HWINTR_H_ + +/** + * @file irq.c + * + * Hardware interrupts routines management. + */ + +#include <sos/errno.h> + +#define sos_save_flags(flags) \ + asm volatile("pushfl ; popl %0":"=g"(flags)::"memory") +#define sos_restore_flags(flags) \ + asm volatile("push %0; popfl"::"g"(flags):"memory") + +#define sos_disable_IRQs(flags) \ + ({ sos_save_flags(flags); asm("cli\n"); }) +#define sos_restore_IRQs(flags) \ + sos_restore_flags(flags) + +/* Usual IRQ levels */ +#define SOS_IRQ_TIMER 0 +#define SOS_IRQ_KEYBOARD 1 +#define SOS_IRQ_SLAVE_PIC 2 +#define SOS_IRQ_COM2 3 +#define SOS_IRQ_COM1 4 +#define SOS_IRQ_LPT2 5 +#define SOS_IRQ_FLOPPY 6 +#define SOS_IRQ_LPT1 7 +#define SOS_IRQ_8_NOT_DEFINED 8 +#define SOS_IRQ_RESERVED_1 9 +#define SOS_IRQ_RESERVED_2 10 +#define SOS_IRQ_RESERVED_3 11 +#define SOS_IRQ_RESERVED_4 12 +#define SOS_IRQ_COPROCESSOR 13 +#define SOS_IRQ_HARDDISK 14 +#define SOS_IRQ_RESERVED_5 15 + +typedef void (*sos_irq_handler_t)(int irq_level); + +/** Setup the PIC */ +sos_ret_t sos_irq_setup(void); + +/** + * If the routine is not NULL, the IDT is setup to call an IRQ + * wrapper upon interrupt, which in turn will call the routine, and + * the PIC is programmed to raise an irq.\ If the routine is + * NULL, we disable the irq line. + */ +sos_ret_t sos_irq_set_routine(int irq_level, + sos_irq_handler_t routine); + +sos_irq_handler_t sos_irq_get_routine(int irq_level); + +#endif /* _SOS_HWINTR_H_ */ diff --git a/sos-code-article3/hwcore/irq_wrappers.S b/sos-code-article3/hwcore/irq_wrappers.S new file mode 100644 index 0000000..cf3355d --- /dev/null +++ b/sos-code-article3/hwcore/irq_wrappers.S @@ -0,0 +1,173 @@ +/* Copyright (C) 2004 The KOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#define ASM_SOURCE 1 + +.file "irq_wrappers.S" + +.text + +/* The address of the table of handlers (defined in irq.c) */ +.extern sos_irq_handler_array + +/* The address of the table of wrappers (defined below, and shared + with irq.c */ +.globl sos_irq_wrapper_array + + +/* These pre-handlers are for IRQ (Master PIC) */ +.irp id, 0,1,2,3,4,5,6,7 + + .p2align 2, 0x90 + + sos_irq_wrapper_\id: + .type sos_irq_wrapper_\id,@function + + /* + * Backup the CPU context + */ + + /* Fake error code */ + pushl $0 + + /* Backup the actual context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Send EOI to PIC. See Intel 8259 datasheet + available on Kos website */ + movb $0x20, %al + outb %al, $0x20 + + /* + * Call the handler with IRQ number as argument + */ + pushl $\id + leal sos_irq_handler_array,%edi + call *\id*4(%edi) + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + + /* Remove fake error code */ + addl $4, %esp + + iret + .endr + + +/* These pre-handlers are for IRQ (Slave PIC) */ +.irp id, 8,9,10,11,12,13,14,15 + + .p2align 2, 0x90 + + sos_irq_wrapper_\id: + .type sos_irq_wrapper_\id,@function + + /* + * Backup the CPU context + */ + + /* Fake error code */ + pushl $0 + + /* Backup the actual context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Send EOI to PIC. See Intel 8259 datasheet + available on Kos website */ + movb $0x20, %al + outb %al, $0xa0 + outb %al, $0x20 + + /* + * Call the handler with IRQ number as argument + */ + pushl $\id + leal sos_irq_handler_array,%edi + call *\id*4(%edi) + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + + /* Remove fake error code */ + addl $4, %esp + + iret + .endr + +/* Build the sos_irq_wrapper_array, shared with irq.c */ +.section ".rodata" +.p2align 5, 0x0 +sos_irq_wrapper_array: + .irp id, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .long (sos_irq_wrapper_\id) + .endr diff --git a/sos-code-article3/hwcore/segment.h b/sos-code-article3/hwcore/segment.h new file mode 100644 index 0000000..37bdf5e --- /dev/null +++ b/sos-code-article3/hwcore/segment.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_HWSEGS_H_ +#define _SOS_HWSEGS_H_ + +/** + * @file segments.h + * + * Global and local (GDT/LDT) segment descriptor definition and + * structure. These segments map virtual addresses (ie + * data/instruction addresses, relative to these segment descriptors) + * to linear addresses (ie addresses in the paged-memory space). + * + * @see Intel x86 doc, vol 3 chapter 3. + */ + +#include <sos/types.h> + +/* + * Global segment selectors (GDT) for SOS/x86. + * + * @see gdt.h + */ +#define SOS_SEG_NULL 0 /* NULL segment, unused by the procesor */ +#define SOS_SEG_KCODE 1 /* Kernel code segment */ +#define SOS_SEG_KDATA 2 /* Kernel data segment */ + + +/** + * Helper macro that builds a segment register's value + */ +#define SOS_BUILD_SEGMENT_REG_VALUE(desc_privilege,in_ldt,seg_index) \ + ( (((desc_privilege) & 0x3) << 0) \ + | (((in_ldt)?1:0) << 2) \ + | ((seg_index) << 3) ) + + +/* + * Local segment selectors (LDT) for SOS/x86 + */ +/* None */ + +#endif /* _SOS_HWSEGS_H_ */ diff --git a/sos-code-article3/sos/assert.h b/sos-code-article3/sos/assert.h new file mode 100644 index 0000000..a14ca0b --- /dev/null +++ b/sos-code-article3/sos/assert.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2004 The KOS Team + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_ASSERT_H_ +#define _SOS_ASSERT_H_ + +#include <drivers/bochs.h> +#include <drivers/x86_videomem.h> + +/** + * If the expr is FALSE, print a message and halt the machine + */ +#define SOS_ASSERT_FATAL(expr) \ + ({ \ + int __res=(int)(expr); \ + if (! __res) { \ + asm("cli\n"); /* disable interrupts -- x86 only */ \ + sos_bochs_printf("%s@%s:%d Assertion " # expr " failed\n", \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + sos_x86_videomem_printf(24, 0, 12, \ + "%s@%s:%d Assertion " # expr " failed", \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + for (;;) asm("hlt;") ; /* Infinite loop, ie simple system halt */ \ + } \ + }) + + +#endif /* _SOS_ASSERT_H_ */ diff --git a/sos-code-article3/sos/errno.h b/sos-code-article3/sos/errno.h new file mode 100644 index 0000000..2c7bada --- /dev/null +++ b/sos-code-article3/sos/errno.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_ERRNO_H_ +#define _SOS_ERRNO_H_ + +/** + * @file errno.h + * + * SOS return value codes and errors. + */ + +/* Positive values of the error codes */ +#define SOS_OK 0 /* No error */ +#define SOS_EINVAL 1 /* Invalid argument */ +#define SOS_ENOSUP 2 /* Operation not supported */ +#define SOS_ENOMEM 3 /* No available memory */ +#define SOS_EFATAL 255 /* Internal fatal error */ + +/* A negative value means that an error occured. For + * example -SOS_EINVAL means that the error was "invalid + * argument" */ +typedef int sos_ret_t; + +#endif /* _SOS_ERRNO_H_ */ diff --git a/sos-code-article3/sos/klibc.c b/sos-code-article3/sos/klibc.c new file mode 100644 index 0000000..277a15c --- /dev/null +++ b/sos-code-article3/sos/klibc.c @@ -0,0 +1,271 @@ +/* Copyright (C) 2004 David Decotigny (with INSA Rennes for vsnprintf) + Copyright (C) 2003 The KOS Team + Copyright (C) 1999 Free Software Foundation + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "klibc.h" + +/* For an optimized version, see BSD sources ;) */ +void *memcpy(void *dst0, const void *src0, register unsigned int size) +{ + char *dst; + const char *src; + for (dst = (char*)dst0, src = (const char*)src0 ; + size > 0 ; + dst++, src++, size--) + *dst = *src; + return dst0; +} + +/* ditto */ +void *memset(void *dst0, register int c, register unsigned int length) +{ + char *dst; + for (dst = (char*) dst0 ; + length > 0 ; + dst++, length --) + *dst = (char)c; + return dst0; +} + +int memcmp(const void *s1, const void *s2, sos_size_t len) +{ + const unsigned char *c1, *c2; + unsigned int i; + + for (i = 0, c1 = s1, c2 = s2; i < len; i++, c1++, c2++) + { + if(*c1 != *c2) + return *c1 - *c2; + } + + return 0; +} + + +unsigned int strlen(register const char *str) +{ + unsigned int retval = 0; + + while (*str++) + retval++; + + return retval; +} + + +unsigned int strnlen(const char * s, sos_size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */continue; + + return sc - s; +} + + +char *strzcpy(register char *dst, register const char *src, register int len) +{ + int i; + + if (len <= 0) + return dst; + + for (i = 0; i < len; i++) + { + dst[i] = src[i]; + if(src[i] == '\0') + return dst; + } + + dst[len-1] = '\0'; + return dst; +} + + +char *strzcat (char *dest, const char *src, sos_size_t n) +{ + char *res = dest; + + for ( ; *dest ; dest++); + + for ( ; *src ; src++, dest++) { + *dest = *src; + n--; + if (n <= 0) + break; + } + + *dest = '\0'; + return res; +} + +int strcmp(register const char *s1, register const char *s2) +{ + while (*s1 == *s2++) + if (*s1++ == 0) + return (0); + + return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); +} + + +int strncmp(register const char *s1, register const char *s2, register int len) +{ + char c1 = '\0', c2 = '\0'; + + while (len > 0) + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + len--; + } + + return c1 - c2; +} + + +/* I (d2) borrowed and rewrote this for Nachos/INSA Rennes. Thanks to + them for having kindly allowed me to do so. */ +int vsnprintf(char *buff, sos_size_t len, const char * format, va_list ap) +{ + sos_size_t i, result; + + if (!buff || !format || (len < 0)) + return -1; + +#define PUTCHAR(thechar) \ + do { \ + if (result < len-1) \ + *buff++ = (thechar); \ + result++; \ + } while (0) + + result = 0; + for(i=0 ; format[i] != '\0' ; i++){ + switch (format[i]) + { + case '%': + i++; + switch(format[i]) + { + case '%': + { + PUTCHAR('%'); + break; + } + case 'i':; + case 'd': + { + int integer = va_arg(ap,int); + int cpt2 = 0; + char buff_int[16]; + + if (integer<0) + PUTCHAR('-'); + /* Ne fait pas integer = -integer ici parce que INT_MIN + n'a pas d'equivalent positif (int = [-2^31, 2^31-1]) */ + + do { + int m10 = integer%10; + m10 = (m10 < 0)? -m10:m10; + buff_int[cpt2++]=(char)('0'+ m10); + integer=integer/10; + } while(integer!=0); + + for(cpt2 = cpt2 - 1 ; cpt2 >= 0 ; cpt2--) + PUTCHAR(buff_int[cpt2]); + + break; + } + + case 'c': + { + int value = va_arg(ap,int); + PUTCHAR((char)value); + break; + } + + case 's': + { + char *string = va_arg(ap,char *); + if (! string) + string = "(null)"; + for( ; *string != '\0' ; string++) + PUTCHAR(*string); + break; + } + + case 'x': + { + unsigned int hexa = va_arg(ap,int); + unsigned int nb; + int i, had_nonzero = 0; + for(i=0 ; i < 8 ; i++) + { + nb = (unsigned int)(hexa << (i*4)); + nb = (nb >> 28) & 0xf; + // Skip the leading zeros + if (nb == 0) + { + if (had_nonzero) + PUTCHAR('0'); + } + else + { + had_nonzero = 1; + if (nb < 10) + PUTCHAR('0'+nb); + else + PUTCHAR('a'+(nb-10)); + } + } + if (! had_nonzero) + PUTCHAR('0'); + break; + } + break; + + default: + PUTCHAR('%'); + PUTCHAR(format[i]); + } + break; + + default: + PUTCHAR(format[i]); + } + } + + *buff = '\0'; + return result; +} + + +int snprintf(char * buff, sos_size_t len, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + len = vsnprintf(buff, len, format, ap); + va_end(ap); + + return len; +} diff --git a/sos-code-article3/sos/klibc.h b/sos-code-article3/sos/klibc.h new file mode 100644 index 0000000..a8b9d49 --- /dev/null +++ b/sos-code-article3/sos/klibc.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2003 The KOS Team + Copyright (C) 1999 Free Software Foundation + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_KLIBC_H_ +#define _SOS_KLIBC_H_ + +/** + * @file klibc.h + * + * Basic libc-style support for common useful functions (string.h, + * stdarg.h), some with slight non-standard behavior (see comments). + */ + +#include <sos/types.h> + +/* string.h functions */ + +void *memcpy(void *dst, const void *src, register unsigned int size ) ; +void *memset(void *dst, register int c, register unsigned int length ) ; +int memcmp(const void *s1, const void *s2, sos_size_t n); + +unsigned int strlen( register const char *str) ; +unsigned int strnlen(const char * s, sos_size_t maxlen); + +/** + * @note Same as strncpy(), with a slightly different semantic. + * Actually, strncpy(3C) says " The result will not be null-terminated + * if the length of 'from' is n or more.". Here, 'dst' is ALWAYS + * null-terminated. And its total len will ALWAYS be <= len, with + * null-terminating-char included. + */ +char *strzcpy( register char *dst, register const char *src, + register int len ) ; + +/** + * @note Same as strncat(), with the same semantic : 'dst' is ALWAYS + * null-terminated. And its total len will ALWAYS be <= len, with + * null-terminating-char included. + */ +char *strzcat (char *dest, const char *src, + const sos_size_t len); + +int strcmp(register const char *s1, register const char *s2 ); +int strncmp(register const char *s1, register const char *s2, + register int len ); + +/* Basic stdarg.h macros. Taken from gcc support files */ +#define __GNUC_VA_LIST +typedef void *__gnuc_va_list; +typedef __gnuc_va_list va_list; +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) +#define va_start(AP, LASTARG) \ + (AP = ((__gnuc_va_list) __builtin_next_arg (LASTARG))) +#define va_end(AP) \ + ((void)0) +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE)))) +#define __va_copy(dest, src) \ + (dest) = (src) + +/* stdarg.h functions. There might be a non-standard behavior: there + will always be a trailing '\0' in the resulting string */ +int vsnprintf(char *, sos_size_t, const char *, va_list); +int snprintf(char *, sos_size_t, const char *, /*args*/ ...) + __attribute__ ((format (printf, 3, 4))); + +#endif /* _SOS_KLIBC_H_ */ diff --git a/sos-code-article3/sos/list.h b/sos-code-article3/sos/list.h new file mode 100644 index 0000000..67e72f3 --- /dev/null +++ b/sos-code-article3/sos/list.h @@ -0,0 +1,186 @@ +/* Copyright (C) 2001 David Decotigny + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_LIST_H_ +#define _SOS_LIST_H_ + +/** + * @file list.h + * + * Circular doubly-linked lists implementation entirely based on C + * macros + */ + + +/* *_named are used when next and prev links are not exactly next + and prev. For instance when we have next_in_team, prev_in_team, + prev_global and next_global */ + +#define list_init_named(list,prev,next) \ + ((list) = NULL) + +#define list_singleton_named(list,item,prev,next) ({ \ + (item)->next = (item)->prev = (item); \ + (list) = (item); \ +}) + +#define list_is_empty_named(list,prev,next) \ + ((list) == NULL) + +#define list_get_head_named(list,prev,next) \ + (list) + +#define list_get_tail_named(list,prev,next) \ + ((list)?((list)->prev):NULL) + +/* Internal macro : insert before the head == insert at tail */ +#define __list_insert_atleft_named(before_this,item,prev,next) ({ \ + (before_this)->prev->next = (item); \ + (item)->prev = (before_this)->prev; \ + (before_this)->prev = (item); \ + (item)->next = (before_this); \ +}) + +/* @note Before_this and item are expected to be valid ! */ +#define list_insert_before_named(list,before_this,item,prev,next) ({ \ + __list_insert_atleft_named(before_this,item,prev,next); \ + if ((list) == (before_this)) (list) = (item); \ +}) + +/** @note After_this and item are expected to be valid ! */ +#define list_insert_after_named(list,after_this,item,prev,next) ({ \ + (after_this)->next->prev = (item); \ + (item)->next = (after_this)->next; \ + (after_this)->next = (item); \ + (item)->prev = (after_this); \ +}) + +#define list_add_head_named(list,item,prev,next) ({ \ + if (list) \ + list_insert_before_named(list,list,item,prev,next); \ + else \ + list_singleton_named(list,item,prev,next); \ + (list) = (item); \ +}) + +#define list_add_tail_named(list,item,prev,next) ({ \ + if (list) \ + __list_insert_atleft_named(list,item,prev,next); \ + else \ + list_singleton_named(list,item,prev,next); \ +}) + +/** @note NO check whether item really is in list ! */ +#define list_delete_named(list,item,prev,next) ({ \ + if ( ((item)->next == (item)) && ((item)->prev == (item)) ) \ + (item)->next = (item)->prev = (list) = NULL; \ + else { \ + (item)->prev->next = (item)->next; \ + (item)->next->prev = (item)->prev; \ + if ((item) == (list)) (list) = (item)->next; \ + (item)->prev = (item)->next = NULL; \ + } \ +}) + +#define list_pop_head_named(list,prev,next) ({ \ + typeof(list) __ret_elt = (list); \ + list_delete_named(list,__ret_elt,prev,next); \ + __ret_elt; }) + +/** Loop statement that iterates through all of its elements, from + head to tail */ +#define list_foreach_forward_named(list,iterator,nb_elements,prev,next) \ + for (nb_elements=0, (iterator) = (list) ; \ + (iterator) && (!nb_elements || ((iterator) != (list))) ; \ + nb_elements++, (iterator) = (iterator)->next ) + +/** Loop statement that iterates through all of its elements, from + tail back to head */ +#define list_foreach_backward_named(list,iterator,nb_elements,prev,next) \ + for (nb_elements=0, (iterator) = list_get_tail_named(list,prev,next) ; \ + (iterator) && (!nb_elements || \ + ((iterator) != list_get_tail_named(list,prev,next))) ; \ + nb_elements++, (iterator) = (iterator)->prev ) + +#define list_foreach_named list_foreach_forward_named + +/** True when we exitted early from the foreach loop (ie break) */ +#define list_foreach_early_break(list,iterator,nb_elements) \ + ((list) && ( \ + ((list) != (iterator)) || \ + ( ((list) == (iterator)) && (nb_elements == 0)) )) + +/** Loop statement that also removes the item at each iteration */ +#define list_collapse_named(list,iterator,prev,next) \ + for ( ; ({ ((iterator) = (list)) ; \ + if (list) list_delete_named(list,iterator,prev,next) ; \ + (iterator); }) ; ) + + +/* + * the same macros : assume that the prev and next fields are really + * named "prev" and "next" + */ + +#define list_init(list) \ + list_init_named(list,prev,next) + +#define list_singleton(list,item) \ + list_singleton_named(list,item,prev,next) + +#define list_is_empty(list) \ + list_is_empty_named(list,prev,next) + +#define list_get_head(list) \ + list_get_head_named(list,prev,next) \ + +#define list_get_tail(list) \ + list_get_tail_named(list,prev,next) \ + +/* @note Before_this and item are expected to be valid ! */ +#define list_insert_after(list,after_this,item) \ + list_insert_after_named(list,after_this,item,prev,next) + +/* @note After_this and item are expected to be valid ! */ +#define list_insert_before(list,before_this,item) \ + list_insert_before_named(list,before_this,item,prev,next) + +#define list_add_head(list,item) \ + list_add_head_named(list,item,prev,next) + +#define list_add_tail(list,item) \ + list_add_tail_named(list,item,prev,next) + +/* @note NO check whether item really is in list ! */ +#define list_delete(list,item) \ + list_delete_named(list,item,prev,next) + +#define list_pop_head(list) \ + list_pop_head_named(list,prev,next) + +#define list_foreach_forward(list,iterator,nb_elements) \ + list_foreach_forward_named(list,iterator,nb_elements,prev,next) + +#define list_foreach_backward(list,iterator,nb_elements) \ + list_foreach_backward_named(list,iterator,nb_elements,prev,next) + +#define list_foreach list_foreach_forward + +#define list_collapse(list,iterator) \ + list_collapse_named(list,iterator,prev,next) + +#endif /* _SOS_LIST_H_ */ diff --git a/sos-code-article3/sos/macros.h b/sos-code-article3/sos/macros.h new file mode 100644 index 0000000..b08f081 --- /dev/null +++ b/sos-code-article3/sos/macros.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2004 The KOS Team + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_MACROS_H_ +#define _SOS_MACROS_H_ + +/** Align on a boundary (MUST be a power of 2), so that return value <= val */ +#define SOS_ALIGN_INF(val,boundary) \ + (((unsigned)(val)) & (~((boundary)-1))) + +/** Align on a boundary (MUST be a power of 2), so that return value >= val */ +#define SOS_ALIGN_SUP(val,boundary) \ + ({ unsigned int __bnd=(boundary); \ + (((((unsigned)(val))-1) & (~(__bnd - 1))) + __bnd); }) + +/** + * @return TRUE if val is a power of 2. + * @note val is evaluated multiple times + */ +#define SOS_IS_POWER_OF_2(val) \ + ((((val) - 1) & (val)) == 0) + +#endif /* _SOS_MACROS_H_ */ diff --git a/sos-code-article3/sos/main.c b/sos-code-article3/sos/main.c new file mode 100644 index 0000000..3cce935 --- /dev/null +++ b/sos-code-article3/sos/main.c @@ -0,0 +1,236 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +/* Include definitions of the multiboot standard */ +#include <bootstrap/multiboot.h> +#include <hwcore/idt.h> +#include <hwcore/gdt.h> +#include <hwcore/irq.h> +#include <hwcore/exception.h> +#include <hwcore/i8254.h> +#include <sos/list.h> +#include <sos/physmem.h> +#include <sos/klibc.h> +#include <sos/assert.h> +#include <drivers/x86_videomem.h> +#include <drivers/bochs.h> + + +/* Helper function to display each bits of a 32bits integer on the + screen as dark or light carrets */ +static void display_bits(unsigned char row, unsigned char col, + unsigned char attribute, + sos_ui32_t integer) +{ + int i; + /* Scan each bit of the integer, MSb first */ + for (i = 31 ; i >= 0 ; i--) + { + /* Test if bit i of 'integer' is set */ + int bit_i = (integer & (1 << i)); + /* Ascii 219 => dark carret, Ascii 177 => light carret */ + unsigned char ascii_code = bit_i?219:177; + sos_x86_videomem_putchar(row, col++, + attribute, + ascii_code); + } +} + + +/* Clock IRQ handler */ +static void clk_it(int intid) +{ + static sos_ui32_t clock_count = 0; + + display_bits(0, 48, + SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE, + clock_count); + clock_count++; + +} + +#define MY_PPAGE_NUM_INT 511 +struct my_ppage +{ + sos_ui32_t before[MY_PPAGE_NUM_INT]; + struct my_ppage *prev, *next; + sos_ui32_t after[MY_PPAGE_NUM_INT]; +}; /* sizeof() Must be <= 4kB */ + +static void test_physmem() +{ + /* We place the pages we did allocate here */ + struct my_ppage *ppage_list, *my_ppage; + sos_count_t num_alloc_ppages = 0, num_free_ppages = 0; + + ppage_list = NULL; + while ((my_ppage = (struct my_ppage*)sos_physmem_ref_physpage_new(FALSE)) + != NULL) + { + int i; + num_alloc_ppages++; + + /* Print the allocation status */ + sos_x86_videomem_printf(2, 0, + SOS_X86_VIDEO_FG_YELLOW + | SOS_X86_VIDEO_BG_BLUE, + "Could allocate %d pages ", + num_alloc_ppages); + + /* We fill this page with its address */ + for (i = 0 ; i < MY_PPAGE_NUM_INT ; i++) + my_ppage->before[i] = my_ppage->after[i] = (sos_ui32_t)my_ppage; + + /* We add this page at the tail of our list of ppages */ + list_add_tail(ppage_list, my_ppage); + } + + /* Now we release these pages in FIFO order */ + while ((my_ppage = list_pop_head(ppage_list)) != NULL) + { + /* We make sure this page was not overwritten by any unexpected + value */ + int i; + for (i = 0 ; i < MY_PPAGE_NUM_INT ; i++) + { + /* We don't get what we expect ! */ + if ((my_ppage->before[i] != (sos_ui32_t)my_ppage) + || (my_ppage->after[i] != (sos_ui32_t)my_ppage)) + { + /* STOP ! */ + sos_x86_videomem_putstring(20, 0, + SOS_X86_VIDEO_FG_LTRED + | SOS_X86_VIDEO_BG_BLUE, + "Page overwritten"); + return; + } + } + + /* Release the descriptor */ + if (sos_physmem_unref_physpage((sos_paddr_t)my_ppage) < 0) + { + /* STOP ! */ + sos_x86_videomem_putstring(20, 0, + SOS_X86_VIDEO_FG_LTRED + | SOS_X86_VIDEO_BG_BLUE, + "Cannot release page"); + return; + } + + /* Print the deallocation status */ + num_free_ppages ++; + sos_x86_videomem_printf(2, 0, + SOS_X86_VIDEO_FG_YELLOW + | SOS_X86_VIDEO_BG_BLUE, + "Could free %d pages ", + num_free_ppages); + } + + /* Print the overall stats */ + sos_x86_videomem_printf(2, 0, + SOS_X86_VIDEO_FG_LTGREEN + | SOS_X86_VIDEO_BG_BLUE, + "Could allocate %d bytes, could free %d bytes ", + num_alloc_ppages << SOS_PAGE_SHIFT, + num_free_ppages << SOS_PAGE_SHIFT); + + SOS_ASSERT_FATAL(num_alloc_ppages == num_free_ppages); +} + + +/* The C entry point of our operating system */ +void sos_main(unsigned long magic, unsigned long addr) +{ + unsigned i; + sos_paddr_t sos_kernel_core_base_paddr, sos_kernel_core_top_paddr; + + /* Grub sends us a structure, called multiboot_info_t with a lot of + precious informations about the system, see the multiboot + documentation for more information. */ + multiboot_info_t *mbi; + mbi = (multiboot_info_t *) addr; + + /* Setup bochs and console, and clear the console */ + sos_bochs_setup(); + + sos_x86_videomem_setup(); + sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE); + + /* Greetings from SOS */ + if (magic == MULTIBOOT_BOOTLOADER_MAGIC) + /* Loaded with Grub */ + sos_x86_videomem_printf(1, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)", + "SOS", ',', + (unsigned)(mbi->mem_upper >> 10) + 1, + (unsigned)mbi->mem_upper); + else + /* Not loaded with grub */ + sos_x86_videomem_printf(1, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Welcome to SOS"); + + sos_bochs_putstring("Message in a bochs\n"); + + /* Setup CPU segmentation and IRQ subsystem */ + sos_gdt_setup(); + sos_idt_setup(); + + /* Setup SOS IRQs and exceptions subsystem */ + sos_exceptions_setup(); + sos_irq_setup(); + + /* Configure the timer so as to raise the IRQ0 at a 100Hz rate */ + sos_i8254_set_frequency(100); + + + /* We need a multiboot-compliant boot loader to get the size of the RAM */ + if (magic != MULTIBOOT_BOOTLOADER_MAGIC) + { + sos_x86_videomem_putstring(20, 0, + SOS_X86_VIDEO_FG_LTRED + | SOS_X86_VIDEO_BG_BLUE + | SOS_X86_VIDEO_FG_BLINKING, + "I'm not loaded with Grub !"); + /* STOP ! */ + for (;;) + continue; + } + + /* Binding some HW interrupts and exceptions to software routines */ + sos_irq_set_routine(SOS_IRQ_TIMER, + clk_it); + /* Enabling the HW interrupts here, this will make the timer HW + interrupt call our clk_it handler */ + asm volatile ("sti\n"); + /* Multiboot says: "The value returned for upper memory is maximally + the address of the first upper memory hole minus 1 megabyte.". It + also adds: "It is not guaranteed to be this value." aka "YMMV" ;) */ + sos_physmem_setup((mbi->mem_upper<<10) + (1<<20), + & sos_kernel_core_base_paddr, + & sos_kernel_core_top_paddr); + test_physmem(); + + /* An operatig system never ends */ + for (;;) + continue; + + return; +} diff --git a/sos-code-article3/sos/physmem.c b/sos-code-article3/sos/physmem.c new file mode 100644 index 0000000..99cffb7 --- /dev/null +++ b/sos-code-article3/sos/physmem.c @@ -0,0 +1,269 @@ +/* Copyright (C) 2004 David Decotigny + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <sos/list.h> +#include <sos/macros.h> +#include <sos/assert.h> +#include <sos/klibc.h> + +#include "physmem.h" + +/** A descriptor for a physical page in SOS */ +struct physical_page_descr +{ + /** The physical base address for the page */ + sos_paddr_t paddr; + + /** The reference count for this physical page. > 0 means that the + page is in the used list. */ + sos_count_t ref_cnt; + + /** The other pages on the list (used, free) */ + struct physical_page_descr *prev, *next; +}; + +/** These are some markers present in the executable file (see sos.lds) */ +extern char __b_kernel, __e_kernel; + +/** The array of ppage descriptors will be located at this address */ +#define PAGE_DESCR_ARRAY_ADDR \ + SOS_PAGE_ALIGN_SUP((sos_paddr_t) (& __e_kernel)) +static struct physical_page_descr * physical_page_descr_array; + +/** The list of physical pages currently available */ +static struct physical_page_descr *free_ppage; + +/** The list of physical pages currently in use */ +static struct physical_page_descr *used_ppage; + +/** We will store here the interval of valid physical addresses */ +static sos_paddr_t physmem_base, physmem_top; + +/** We store the number of pages used/free */ +static sos_count_t physmem_total_pages, physmem_used_pages; + +sos_ret_t sos_physmem_setup(sos_size_t ram_size, + /* out */sos_paddr_t *kernel_core_base, + /* out */sos_paddr_t *kernel_core_top) +{ + /* The iterator over the page descriptors */ + struct physical_page_descr *ppage_descr; + + /* The iterator over the physical addresses */ + sos_paddr_t ppage_addr; + + /* Make sure ram size is aligned on a page boundary */ + ram_size = SOS_PAGE_ALIGN_INF(ram_size);/* Yes, we may lose at most a page */ + + /* Reset the used/free page lists before building them */ + free_ppage = used_ppage = NULL; + physmem_total_pages = physmem_used_pages = 0; + + /* Make sure that there is enough memory to store the array of page + descriptors */ + *kernel_core_base = SOS_PAGE_ALIGN_INF((sos_paddr_t)(& __b_kernel)); + *kernel_core_top + = PAGE_DESCR_ARRAY_ADDR + + SOS_PAGE_ALIGN_SUP( (ram_size >> SOS_PAGE_SHIFT) + * sizeof(struct physical_page_descr)); + if (*kernel_core_top > ram_size) + return -SOS_ENOMEM; + + /* Page 0-4kB is not available in order to return address 0 as a + means to signal "no page available" */ + physmem_base = SOS_PAGE_SIZE; + physmem_top = ram_size; + + /* Setup the page descriptor arrray */ + physical_page_descr_array + = (struct physical_page_descr*)PAGE_DESCR_ARRAY_ADDR; + + /* Scan the list of physical pages */ + for (ppage_addr = 0, + ppage_descr = physical_page_descr_array ; + ppage_addr < physmem_top ; + ppage_addr += SOS_PAGE_SIZE, + ppage_descr ++) + { + enum { PPAGE_MARK_RESERVED, PPAGE_MARK_FREE, + PPAGE_MARK_KERNEL, PPAGE_MARK_HWMAP } todo; + + memset(ppage_descr, 0x0, sizeof(struct physical_page_descr)); + + /* Init the page descriptor for this page */ + ppage_descr->paddr = ppage_addr; + + /* Reserved : 0 ... base */ + if (ppage_addr < physmem_base) + todo = PPAGE_MARK_RESERVED; + + /* Free : base ... BIOS */ + else if ((ppage_addr >= physmem_base) + && (ppage_addr < BIOS_N_VIDEO_START)) + todo = PPAGE_MARK_FREE; + + /* Used : BIOS */ + else if ((ppage_addr >= BIOS_N_VIDEO_START) + && (ppage_addr < BIOS_N_VIDEO_END)) + todo = PPAGE_MARK_HWMAP; + + /* Free : BIOS ... kernel */ + else if ((ppage_addr >= BIOS_N_VIDEO_END) + && (ppage_addr < (sos_paddr_t) (& __b_kernel))) + todo = PPAGE_MARK_FREE; + + /* Used : Kernel code/data/bss + physcal page descr array */ + else if ((ppage_addr >= *kernel_core_base) + && (ppage_addr < *kernel_core_top)) + todo = PPAGE_MARK_KERNEL; + + /* Free : first page of descr ... end of RAM */ + else + todo = PPAGE_MARK_FREE; + + /* Actually does the insertion in the used/free page lists */ + physmem_total_pages ++; + switch (todo) + { + case PPAGE_MARK_FREE: + ppage_descr->ref_cnt = 0; + list_add_head(free_ppage, ppage_descr); + break; + + case PPAGE_MARK_KERNEL: + case PPAGE_MARK_HWMAP: + ppage_descr->ref_cnt = 1; + list_add_head(used_ppage, ppage_descr); + physmem_used_pages ++; + break; + + default: + /* Reserved page: nop */ + break; + } + } + + return SOS_OK; +} + + +sos_paddr_t sos_physmem_ref_physpage_new(sos_bool_t can_block) +{ + struct physical_page_descr *ppage_descr; + + if (! free_ppage) + return (sos_paddr_t)NULL; + + /* Retrieve a page in the free list */ + ppage_descr = list_pop_head(free_ppage); + + /* The page is assumed not to be already used */ + SOS_ASSERT_FATAL(ppage_descr->ref_cnt == 0); + + /* Mark the page as used (this of course sets the ref count to 1) */ + ppage_descr->ref_cnt ++; + + /* Put the page in the used list */ + list_add_tail(used_ppage, ppage_descr); + physmem_used_pages ++; + + return ppage_descr->paddr; +} + + +/** + * Helper function to get the physical page descriptor for the given + * physical page address. + * + * @return NULL when out-of-bounds or non-page-aligned + */ +inline static struct physical_page_descr * +get_page_descr_at_paddr(sos_paddr_t ppage_paddr) +{ + /* Don't handle non-page-aligned addresses */ + if (ppage_paddr & SOS_PAGE_MASK) + return NULL; + + /* Don't support out-of-bounds requests */ + if ((ppage_paddr < physmem_base) || (ppage_paddr >= physmem_top)) + return NULL; + + return physical_page_descr_array + (ppage_paddr >> SOS_PAGE_SHIFT); +} + + +sos_ret_t sos_physmem_ref_physpage_at(sos_paddr_t ppage_paddr) +{ + struct physical_page_descr *ppage_descr + = get_page_descr_at_paddr(ppage_paddr); + + if (! ppage_descr) + return -SOS_EINVAL; + + /* Increment the reference count for the page */ + ppage_descr->ref_cnt ++; + + /* If the page is newly referenced (ie we are the only owners of the + page => ref cnt == 1), transfer it in the used pages list */ + if (ppage_descr->ref_cnt == 1) + { + list_delete(free_ppage, ppage_descr); + list_add_tail(used_ppage, ppage_descr); + physmem_used_pages ++; + + /* The page is newly referenced */ + return FALSE; + } + + /* The page was already referenced by someone */ + return TRUE; +} + + +sos_ret_t +sos_physmem_unref_physpage(sos_paddr_t ppage_paddr) +{ + /* By default the return value indicates that the page is still + used */ + sos_ret_t retval = FALSE; + + struct physical_page_descr *ppage_descr + = get_page_descr_at_paddr(ppage_paddr); + + if (! ppage_descr) + return -SOS_EINVAL; + + /* Don't do anything if the page is not in the used list */ + if (ppage_descr->ref_cnt <= 0) + return -SOS_EINVAL; + + /* Unreference the page, and, when no mapping is active anymore, put + the page in the free list */ + ppage_descr->ref_cnt--; + if (ppage_descr->ref_cnt <= 0) + { + /* Transfer the page, considered USED, to the free list */ + list_delete(used_ppage, ppage_descr); + physmem_used_pages --; + list_add_head(free_ppage, ppage_descr); + + /* Indicate that the page is now unreferenced */ + retval = TRUE; + } + + return retval; +} diff --git a/sos-code-article3/sos/physmem.h b/sos-code-article3/sos/physmem.h new file mode 100644 index 0000000..8b5d997 --- /dev/null +++ b/sos-code-article3/sos/physmem.h @@ -0,0 +1,119 @@ +/* Copyright (C) 2004 David Decotigny + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_PHYSMEM_H_ +#define _SOS_PHYSMEM_H_ + +/** + * @file physmem.h + * + * Physical pages of memory + */ + +#include <sos/errno.h> +#include <sos/types.h> +#include <sos/macros.h> + +/** The size of a physical page (arch-dependent) */ +#define SOS_PAGE_SIZE (4*1024) + +/** The corresponding shift */ +#define SOS_PAGE_SHIFT 12 /* 4 kB = 2^12 B */ + +/** The corresponding mask */ +#define SOS_PAGE_MASK ((1<<12) - 1) + +#define SOS_PAGE_ALIGN_INF(val) \ + SOS_ALIGN_INF((val), SOS_PAGE_SIZE) +#define SOS_PAGE_ALIGN_SUP(val) \ + SOS_ALIGN_SUP((val), SOS_PAGE_SIZE) + + +/** + * This is the reserved physical interval for the x86 video memory and + * BIOS area. In physmem.c, we have to mark this area as "used" in + * order to prevent from allocating it. And in paging.c, we'd better + * map it in virtual space if we really want to be able to print to + * the screen (for debugging purpose, at least): for this, the + * simplest is to identity-map this area in virtual space (note + * however that this mapping could also be non-identical). + */ +#define BIOS_N_VIDEO_START 0xa0000 +#define BIOS_N_VIDEO_END 0x100000 + + +/** + * Initialize the physical memory subsystem, for the physical area [0, + * ram_size). This routine takes into account the BIOS and video + * areas, to prevent them from future allocations. + * + * @param ram_size The size of the RAM that will be managed by this subsystem + * + * @param kernel_core_base The lowest address for which the kernel + * assumes identity mapping (ie virtual address == physical address) + * will be stored here + * + * @param kernel_core_top The top address for which the kernel + * assumes identity mapping (ie virtual address == physical address) + * will be stored here + */ +sos_ret_t sos_physmem_setup(sos_size_t ram_size, + /* out */sos_paddr_t *kernel_core_base, + /* out */sos_paddr_t *kernel_core_top); + +/** + * Retrieve the total number of pages, and the number of free pages + */ +sos_ret_t sos_physmem_get_state(/* out */sos_count_t *total_ppages, + /* out */sos_count_t *used_ppages); + + +/** + * Get a free page. + * + * @return The (physical) address of the (physical) page allocated, or + * NULL when none currently available. + * + * @param can_block TRUE if the function is allowed to block + * @note The page returned has a reference count equal to 1. + */ +sos_paddr_t sos_physmem_ref_physpage_new(sos_bool_t can_block); + + +/** + * Increment the reference count of a given physical page. Useful for + * VM code which tries to map a precise physical address. + * + * @return TRUE when the page was previously in use, FALSE when the + * page was previously in the free list, <0 when the page address is + * invalid. + */ +sos_ret_t sos_physmem_ref_physpage_at(sos_paddr_t ppage_paddr); + + +/** + * Decrement the reference count of the given physical page. When this + * reference count reaches 0, the page is marked free, ie is available + * for future sos_physmem_get_physpage() + * + * @return FALSE when the page is still in use, TRUE when the page is now + * unreferenced, <0 when the page address is invalid + */ +sos_ret_t sos_physmem_unref_physpage(sos_paddr_t ppage_paddr); + + +#endif /* _SOS_PHYSMEM_H_ */ diff --git a/sos-code-article3/sos/types.h b/sos-code-article3/sos/types.h new file mode 100644 index 0000000..02d9f6d --- /dev/null +++ b/sos-code-article3/sos/types.h @@ -0,0 +1,50 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_TYPES_H_ +#define _SOS_TYPES_H_ + +/** + * @file types.h + * + * SOS basic types definition + */ + +/** Physical address */ +typedef unsigned int sos_paddr_t; + +/** Generic virtual address (kernel or user) */ +typedef unsigned int sos_vaddr_t; + +/** Memory size of an object (positive) */ +typedef unsigned int sos_size_t; +/** Generic count of objects */ +typedef unsigned int sos_count_t; + +/** Low-level sizes */ +typedef unsigned long int sos_ui32_t; /* 32b unsigned */ +typedef unsigned short int sos_ui16_t; /* 16b unsigned */ +typedef unsigned char sos_ui8_t; /* 8b unsigned */ + +typedef enum { FALSE=0, TRUE } sos_bool_t; + +/** Not a proper type, but highly useful with basic type + manipulations */ +#define NULL ((void*)0) + +#endif /* _SOS_TYPES_H_ */ diff --git a/sos-code-article3/support/build_image.sh b/sos-code-article3/support/build_image.sh new file mode 100755 index 0000000..43929cd --- /dev/null +++ b/sos-code-article3/support/build_image.sh @@ -0,0 +1,215 @@ +#!/bin/sh +# Copyright (C) 2003, David Decotigny + +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# 1) What does it do ? +# +# 1) Check where Grub is installed (lookup_grub) +# 2) Assign some local variables using the shell script arguments. +# a) Argument 1 : the destination (either a file or a drive, like a:) +# b) Argument 2 : the loader (i.e kernel) +# c) Argument 3 : options passed to the loader +# d) Argument 4 : the modules (that can be loaded optionally by Grub) +# 3) Test whether destination is a drive or a file +# 4) Create the directory structure inside the drive +# 5) Copy the loader in the drive +# 6) Generate the 'menu.txt' file used by Grub to generate the boot menu +# 7) Copy all modules +# 8) Copy the menu.txt file +# +# 2) Why is it so complex ? +# Because it must support various Grub/mtools installations and versions +# +# In fact, this shell script is used in the KOS (kos.enix.org) +# project. This operating system consists in a loader and many many +# modules that are linked together at boot time. It is much more +# complex that a simple monolithic kernel. +# +# For your simple monolithic kernel, you only need to give argument 1 +# and 2. + +print_usage () { + echo "Usage: $0 [X:|image] path/to/loader option path/to/modules..." + echo " where X: is a valid floppy drive on your computer" + echo " where image is any file name" + exit 1 +} + +grub_dirs_common="/usr/local/share/grub/i386-freebsd /usr/local/share/grub/i386-pc /usr/share/grub/i386-pc /usr/lib/grub/i386-pc /usr/local/grub /usr/share/grub/i386-redhat /usr/local/src/grub-0.5.94 $HOME/share/grub/i386-pc/" +sbin_grub_path="/usr/local/sbin /usr/sbin /sbin $HOME/sbin" + +PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin +export PATH + +MTOOLSRC=mtoolsrc +export MTOOLSRC + +# Redefined variables +FLOPPY_DRIVE=A: +IMG_FNAME=fd.img + +## +## Format disk image +## +init_image () { + echo "Initialize disk image $IMG_FILE..." + if [ ! -f $IMG_FNAME ] ; then + dd if=/dev/zero of=$IMG_FNAME bs=18k count=80 1>/dev/null 2>&1 + fi + + rm -f $MTOOLSRC + echo "drive u: file=\"$IMG_FNAME\" 1.44M filter" > $MTOOLSRC + + if mformat U: ; then : ; else + rm -f $MTOOLSRC + echo "drive u: file=\"$IMG_FNAME\" 1.44M" > $MTOOLSRC + if mformat U: ; then : ; else + rm -f $MTOOLSRC + echo "drive u: file=\"$IMG_FNAME\"" > $MTOOLSRC + mformat U: + fi + fi +} + + +## +## Format (real) floppy disk +## +init_floppy () { + echo "Formatting floppy..." + mformat $FLOPPY_DRIVE || exit 1 +} + + +lookup_grub () { + # Look for a correct GRUBDIR + for d in $grub_dirs_common ; do + if [ -d $d ] ; then + GRUBDIR=$d + break + fi + done + + # Try to guess with locate + if [ ! -d "$GRUBDIR" ] ; then + GRUBDIR=`locate stage2 | head -1 | xargs dirname 2>/dev/null` + fi + + # Look for a correct sbin/grub + for d in $sbin_grub_path ; do + if [ -x $d/grub ] ; then + SBIN_GRUB=$d/grub + break + fi + done + + if [ -d "$GRUBDIR" -a -x "$SBIN_GRUB" ] ; then + echo "Found correct grub installation in $GRUBDIR" + echo "Found correct /sbin/grub at $SBIN_GRUB" + else + echo "Couldn't find a correct grub installation." + exit 1 + fi +} + +## +## setup_disk [drive] +## => setup disk directory structure / copy files +## +setup_disk () { + echo "Setup destination disk..." + + mmd $1/boot + mmd $1/boot/grub + + if [ -d $GRUBDIR/stage1 ] ; then + mcopy $GRUBDIR/stage1/stage1 $1/boot/grub/ + mcopy $GRUBDIR/stage2/stage2 $1/boot/grub/ + else + mcopy $GRUBDIR/stage1 $1/boot/grub/ + mcopy $GRUBDIR/stage2 $1/boot/grub/ + fi + mmd $1/system + mmd $1/modules + + $SBIN_GRUB --batch <<EOT 1>/dev/null 2>/dev/null || exit 1 +device (fd0) $IMG_FNAME +install (fd0)/boot/grub/stage1 (fd0) (fd0)/boot/grub/stage2 p (fd0)/boot/grub/menu.txt +quit +EOT +} + + + +################################################# +## Real start +## +#[ "$#" -lt 3 ] && print_usage + +lookup_grub + +dest="$1" ; shift +loader_fname="$1" ; shift +options="$1" ; shift +modules="$*" + +# Init destination disk +case x$dest in + x*:) + drive=$dest + IMG_FNAME=$dest + FLOPPY_DRIVE=$dest + init_floppy + ;; + x*) + drive=U: + IMG_FNAME=$dest + init_image + ;; +esac + +# Create directory structure +setup_disk $drive + +# Copy the loader +mcopy -bo $loader_fname $drive/system/`basename $loader_fname` + +# Generate the menu.txt file +rm -f menu.txt +cat <<EOF > menu.txt +timeout 0 +default 0 +title Simple OS +root (fd0) +kernel /system/`basename $loader_fname` $options +EOF + +# Copy the modules +for f in $modules ; do + if [ ! -f $f ] ; then + echo "ERROR: module $f not correctly compiled in." + exit 1 + fi + if ! mcopy -bo $f $drive/modules/`basename $f` ; then + echo "ERROR: module $f could not be transferred to floppy." + exit 1 + fi + echo module /modules/`basename $f` >> menu.txt +done + +# Transfers the menu.txt file to floppy +mcopy -bo menu.txt $drive/boot/grub/ diff --git a/sos-code-article3/support/sos.lds b/sos-code-article3/support/sos.lds new file mode 100644 index 0000000..4d87061 --- /dev/null +++ b/sos-code-article3/support/sos.lds @@ -0,0 +1,107 @@ +/* Copyright (C) 2003, Thomas Petazzoni + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +/* We generate binary in the ELF format */ +OUTPUT_FORMAT("elf32-i386","elf32-i386","elf32-i386"); + +/* The entry point is _start (defined in boot.S) */ +ENTRY(_start) + +/* The architecture is i386 */ +OUTPUT_ARCH("i386") + +SECTIONS +{ + /* our kernel is loaded at 0x200000 */ + . = 0x200000; + __b_load = .; + + /* the multiboot header MUST come early enough in the output + object file */ + .multiboot : + { + /* The multiboot section (containing the multiboot header) + goes here */ + *(.multiboot); + + /* + * With the following line, we force this section to be + * allocated in the output file as soon as possible, no matter + * when the file containing the multiboot header (multiboot.S) + * is compiled. This is to conform to the multiboot spec, which + * says "The Multiboot header must be contained completely + * within the first 8192 bytes of the OS image, and must be + * longword (32-bit) aligned." + */ + LONG(0); + } + + /* Defines a symbol '__b_kernel to mark the start of the kernel + code/data */ + . = ALIGN(4096); + __b_kernel = .; + + /* Beginning of the text section */ + .text ALIGN(4096) : + { + /* This section includes the code */ + *(.text*) + /* Defines the 'etext' and '_etext' at the end */ + PROVIDE(etext = .); + PROVIDE(_etext = .); + } + + /* Beginning of the data section */ + .data . : + { *(.data*) + PROVIDE(edata = .); + PROVIDE(_edata = .); + } + + /* Beginning of the read-only data section */ + .rodata . : + { *(.rodata*) + PROVIDE(erodata = .); + PROVIDE(_erodata = .); + } + /* We take note of the end of the data to load */ + __e_load = .; + + /* Beginning of the BSS section (global uninitialized data) */ + .bss SIZEOF(.rodata) + ADDR(.rodata) : + { *(.bss) + *(COMMON) + PROVIDE(ebss = .); + PROVIDE(_ebss = .); + } + + /* We take note of the end of the kernel */ + __e_kernel = .; + + /* We don't care of the note, indent, comment, etc.. sections + generated by gcc */ + /DISCARD/ :{ + *(.note*) + *(.indent) + *(.comment) + *(.stab) + *(.stabstr) + } + +} + diff --git a/sos-code-article4/INSTALL b/sos-code-article4/INSTALL new file mode 100644 index 0000000..7c7d619 --- /dev/null +++ b/sos-code-article4/INSTALL @@ -0,0 +1,118 @@ + + SOS: A Simple Operating System + + Compilation/Installation/Test instructions + + +Compilation +=========== + +IMPORTANT +--------- + +Don't forget to run 'make clean' before 'make' after you have modified +any source or header file(s). + + +On a x86 host where grub is correctly installed +----------------------------------------------- + +Simply run 'make' + + +On a non-x86 host (without grub of course !) +-------------------------------------------- + +See extra/README + + +On an x86 host without Grub, or with a buggy Grub +------------------------------------------------- + +See extra/README + +How do I know I have a buggy grub installation ? Answer: in the qemu +PC emulator, Grub hangs while loading the kernel + + +Installation +============ + +Nothing special to do besides compiling + + +Test the SOS Kernel +=================== + +On a x86 real machine with Grub installed +----------------------------------------- + + 1st method + => Boot the sos.elf file (append 'kernel=<path_to>sos.elf' in the + menu.lst or type it on Grub's command line) from a hard disk, a + floppy, or from the network + + 2nd method + => Copy the file 'fd.img' to a floppy and boot from it + + +On a x86 real machine without Grub installed +-------------------------------------------- + + 1st method + => see extra/README to compile with the grub floppy image we provide, + copy the file 'fd.img' to a floppy, and boot from it + + 2nd method + => see extra/README to compile with the boot sector we provide (up to + article 2 only), copy the file 'extra/sos_bsect.img' to a floppy, + and boot from it + + +Inside a PC emulator (x86 and non-x86 hosts) +-------------------------------------------- + +Tested on both the bochs emulator (x86/linux, sparc/solaris and +ppc/linux hosts, 'apt-get install bochs-x vgabios' on debian +testing/unstable), and the qemu system emulator (with libsdl +installed: 'apt-get install libsdl1.2-dev' on debian +testing/unstable). + + 1/ Grub is installed on the host (x86 hosts only) + - - - - - - - - - - - - - - - - - - - - - - - - - + + bochs: boot from the file 'fd.img'. Example of a ~/.bochsrc: + floppya: 1_44=/home/d2/sos/fd.img, status=inserted + romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000 + vgaromimage: /usr/share/vgabios/vgabios.bin + megs:63 # 63 Mo de RAM + + qemu: run 'qemu -fda fd.img' + If grub hangs while loading the kernel, please go to method 2/ + + 2/ Grub is not installed (all hosts) + - - - - - - - - - - - - - - - - - - + + See extra/README to generate a floppy image with the Grub floppy + image we provide, and: + + bochs: boot from the file 'fd.img' + + qemu: run 'qemu -fda fd.img' + + 3/ Bonus: boot with the bootsector we provide (all hosts, up to art. 2 ONLY !) + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + See extra/README to generate a floppy image with the boot sector we + provide, and: + + bochs: boot from the file 'extra/sos_bsect.img' + + qemu: run 'qemu -fda extra/sos_qemu.img' + + NOTE: After article 2, this way of booting is not supported: please + use the method 2/ above. + + +-- +David Decotigny diff --git a/sos-code-article4/LICENSE b/sos-code-article4/LICENSE new file mode 100644 index 0000000..60549be --- /dev/null +++ b/sos-code-article4/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) 19yy 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. + + <signature of Ty Coon>, 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/sos-code-article4/Makefile b/sos-code-article4/Makefile new file mode 100644 index 0000000..3a2282a --- /dev/null +++ b/sos-code-article4/Makefile @@ -0,0 +1,45 @@ +CC=gcc +CFLAGS = -Wall -nostdlib -nostdinc -ffreestanding -DKERNEL_SOS +LDFLAGS = --warn-common +OBJECTS = bootstrap/multiboot.o \ + hwcore/idt.o hwcore/gdt.o \ + hwcore/exception.o hwcore/exception_wrappers.o \ + hwcore/irq.o hwcore/irq_wrappers.o hwcore/i8259.o \ + hwcore/paging.o \ + hwcore/i8254.o drivers/x86_videomem.o drivers/bochs.o \ + sos/physmem.o sos/klibc.o sos/main.o + +KERNEL_OBJ = sos.elf +MULTIBOOT_IMAGE = fd.img +PWD := $(shell pwd) + +# Main target +all: $(MULTIBOOT_IMAGE) + +$(MULTIBOOT_IMAGE): $(KERNEL_OBJ) + ./support/build_image.sh $@ $< + +$(KERNEL_OBJ): $(OBJECTS) ./support/sos.lds + $(LD) $(LDFLAGS) -T ./support/sos.lds -o $@ $(OBJECTS) + -nm -C $@ | cut -d ' ' -f 1,3 > sos.map + +-include .mkvars + +# Create objects from C source code +%.o: %.c + $(CC) -I$(PWD) -c $< $(CFLAGS) -o $@ + +# Create objects from assembler (.S) source code +%.o: %.S + $(CC) -I$(PWD) -c $< $(CFLAGS) -DASM_SOURCE=1 -o $@ + +# Clean directory +clean: + $(RM) *.img *.o mtoolsrc *~ menu.txt *.img *.elf *.bin *.map + $(RM) *.log *.out bochs* + $(RM) bootstrap/*.o bootstrap/*~ + $(RM) drivers/*.o drivers/*~ + $(RM) hwcore/*.o hwcore/*~ + $(RM) sos/*.o sos/*~ + $(RM) support/*~ + $(RM) extra/*~ diff --git a/sos-code-article4/README b/sos-code-article4/README new file mode 100644 index 0000000..efbbc89 --- /dev/null +++ b/sos-code-article4/README @@ -0,0 +1,90 @@ + + SOS: A Simple Operating System + + +This is SOS, a Simple Operating System for i386-family +processors. This is as simple as possible to show a way to program a +basic Operating System on real common hardware (PC). The code should +be easily readable and understandable thanks to frequent comments, and +references to external documentation. We chose to implement the basic +features of an OS, thus making design decisions targetting towards +simplicity of understanding, covering most of the OS classical +concepts, but not aiming at proposing yet another full-fledged +competitive OS (Linux is quite good at it). However, for those who +would like to propose some enhancements, we are open to any code +suggestions (patches only, please). And yes, there might be bugs in +the code, so please send us any bug report, and/or patches ! + +The OS comes as a set of articles (in french) to be published in the +journal "Linux Magazine France". Each month, the part of the code +related to the current article's theme is released (see VERSION file), +and the resulting OS can be successfully compiled and run, by booting +it from a floppy on a real machine (tested AMD k7, Cyrix and Intel P4 +pentiums), or through an x86 emulator (bochs or qemu). The resulting +OS is available as a multiboot compliant ELF kernel (sos.elf) and as a +floppy image (fd.img). It provides a very very very basic demo whose +aim is to understand how everything works, not to animate sprites on +the screen with 5:1 dolby sound. + +The initial technical features and lack-of-features of the OS are: + - monolithic kernel, fully interruptible, non-preemptible (big kernel + lock), target machines = i386 PC or better + - compiles on any host where the gcc/binutils toolchain (target + i586-gnu) is available. Can be tested on real i486/pentium + hardware, or on any host that can run an i486/pentium PC emulator + (bochs or qemu) + - kernel loaded by grub, or by a sample bootsector (up to article 2 + ONLY) + - clear separation of physical memory and virtual memory concepts, + even inside the kernel: no identity-mapping of the physical memory + inside the kernel (allows to move virtual mappings of kernel pages + at run-time, eg to free ISA DMA pages, and to avercome the 4G RAM + barrier) + - slab-type kernel memory allocation + - no swap, no reverse mapping + - VERY simple drivers: keyboard, x86 video memory, IDE disks + - logical devices: partitions, FAT filesystem, "hard-coded" + mountpoints only (~ MSDOS) + - no network stack + - user-level features: ELF loader (no shared libraries), processes, + user threads (kernel-level scheduling only), mmap API, basic VFS + +To understand where to look at for what, here is a brief description: + - Makefile: the (ONLY) makefile of the OS. Targets are basically + 'all' and 'clean' + - bootstrap/ directory: code to load the kernel. Both the stuff + needed for a multiboot-compliant loader (eg grub) AND a bootsector + are provided. The bootsector may only be used up to article 2. + - sos/ directory: the entry routine for the kernel (main.c), various + systemwide header files, a set of common useful C routines + ("nano-klibc"), and kernel subsystems (kernel memory management, + etc...) + - hwcore/ directory: Low-level CPU- and kernel-related routines + (interrupt/exception management, translation tables and segment + registers, ...) + - drivers/ directory: basic kernel drivers for various (non CPU) + devices (keyboard, x86 video memory, bochs 0xe9 port, ...). Used + mainly for debugging + - support/ directory: scripts and configuration files to build the + floppy images + - extra/ directory: a set of configuration files to be customized for + non-x86 host installations (yes, we primarily develop SOS on a ppc, for + the x86 target of course), or for grub-less installations. See + README file in this directory. + +The code is licensed under the terms of the GNU GPL version 2 (see +LICENSE file). + +Enjoy ! + + David Decotigny, Thomas Petazzoni, the Kos team + http://sos.enix.org/ + http://david.decotigny.free.fr/ + http://kos.enix.org/~thomas/ + http://kos.enix.org/ + + +-- +David Decotigny + +PS: Made with a Mac. diff --git a/sos-code-article4/VERSION b/sos-code-article4/VERSION new file mode 100644 index 0000000..146a301 --- /dev/null +++ b/sos-code-article4/VERSION @@ -0,0 +1,11 @@ +SOS -- Simple OS +Copyright (C) 2003,2004 The SOS Team (David Decotigny & Thomas Petazzoni) + +Version "Article 4" -- Basic routines for x86 mmu supervision + + 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. + + See the LICENSE file included in the distribution. diff --git a/sos-code-article4/bootstrap/multiboot.S b/sos-code-article4/bootstrap/multiboot.S new file mode 100644 index 0000000..4a7c65b --- /dev/null +++ b/sos-code-article4/bootstrap/multiboot.S @@ -0,0 +1,74 @@ +/* Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + + +/* The operating system is booted by Grub, so we almost have nothing + to do to boot it. We only have to conform to the Multiboot + standard, as defined by the Grub documentation */ + +#define ASM 1 +/* The multiboot.h header contains a lot of multiboot standard + definitions */ +#include "multiboot.h" + + /* The multiboot header itself. It must come first. */ +.section ".multiboot" + /* Multiboot header must be aligned on a 4-byte boundary */ + .align 4 +multiboot_header: + /* magic= */ .long MULTIBOOT_HEADER_MAGIC + /* flags= */ .long MULTIBOOT_HEADER_FLAGS + /* checksum= */ .long -(MULTIBOOT_HEADER_MAGIC \ + +MULTIBOOT_HEADER_FLAGS) + /* header_addr= */ .long multiboot_header + /* load_addr= */ .long __b_kernel + /* load_end_addr=*/ .long __e_load + /* bss_end_addr= */ .long __e_kernel + /* entry_addr= */ .long multiboot_entry + +/* Here is the beginning of the code of our operating system */ +.text + +.globl start, _start +start: +_start: +multiboot_entry: + /* Set up a stack */ + movl $(stack + MULTIBOOT_STACK_SIZE), %ebp + movl %ebp, %esp + + /* Set EFLAGS to 0 */ + pushl $0 + /* pop stack into the EFLAGS register */ + popf + + /* Push the magic and the address on the stack, so that they + will be the parameters of the cmain function */ + pushl %ebx + pushl %eax + + /* Call the cmain function (os.c) */ + call EXT_C(sos_main) + + /* Should never get there */ +loop: + hlt + jmp loop + + /* Here is the stack */ +.comm stack, MULTIBOOT_STACK_SIZE diff --git a/sos-code-article4/bootstrap/multiboot.h b/sos-code-article4/bootstrap/multiboot.h new file mode 100644 index 0000000..bee676d --- /dev/null +++ b/sos-code-article4/bootstrap/multiboot.h @@ -0,0 +1,129 @@ +#ifndef __MULTIBOOT_H__ +#define __MULTIBOOT_H__ + +/* multiboot.h - the header for Multiboot */ +/* Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Macros. */ + +/* The magic number for the Multiboot header. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* The flags for the Multiboot header. */ +#define MULTIBOOT_HEADER_FLAGS 0x00010003 + +/* The magic number passed by a Multiboot-compliant boot loader. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* The size of our stack (16KB). */ +#define MULTIBOOT_STACK_SIZE 0x4000 + +#define MULTIBOOT_CMDLINE 4 +#define MULTIBOOT_MODS 8 + +/* C symbol format. HAVE_ASM_USCORE is defined by configure. */ +#ifdef HAVE_ASM_USCORE +# define EXT_C(sym) _ ## sym +#else +# define EXT_C(sym) sym +#endif + +#ifndef ASM +/* Do not include here in boot.S. */ + + + +/* Types. */ + +/* The Multiboot header. */ +typedef struct multiboot_header +{ + unsigned long magic; + unsigned long flags; + unsigned long checksum; + unsigned long header_addr; + unsigned long load_addr; + unsigned long load_end_addr; + unsigned long bss_end_addr; + unsigned long entry_addr; +} multiboot_header_t; + +/* The symbol table for a.out. */ +typedef struct aout_symbol_table +{ + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long reserved; +} aout_symbol_table_t; + +/* The section header table for ELF. */ +typedef struct elf_section_header_table +{ + unsigned long num; + unsigned long size; + unsigned long addr; + unsigned long shndx; +} elf_section_header_table_t; + +/* The Multiboot information. */ +typedef struct multiboot_info +{ + unsigned long flags; + unsigned long mem_lower; + unsigned long mem_upper; + unsigned long boot_device; + unsigned long cmdline; + unsigned long mods_count; + unsigned long mods_addr; + union + { + aout_symbol_table_t aout_sym; + elf_section_header_table_t elf_sec; + } u; + unsigned long mmap_length; + unsigned long mmap_addr; + unsigned long drives_length; + unsigned long drives_addr; +} multiboot_info_t; + +/* The module structure. */ +typedef struct module +{ + unsigned long mod_start; + unsigned long mod_end; + unsigned long string; + unsigned long reserved; +} module_t; + +/* The memory map. Be careful that the offset 0 is base_addr_low + but no size. */ +typedef struct memory_map +{ + unsigned long size; + unsigned long base_addr_low; + unsigned long base_addr_high; + unsigned long length_low; + unsigned long length_high; + unsigned long type; +} memory_map_t; + +void dump_multiboot_info(multiboot_info_t *mbi); + +#endif /* ! ASM */ + +#endif /* __MULTIBOOT_H__ */ diff --git a/sos-code-article4/drivers/bochs.c b/sos-code-article4/drivers/bochs.c new file mode 100644 index 0000000..db18599 --- /dev/null +++ b/sos-code-article4/drivers/bochs.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <hwcore/ioports.h> +#include <sos/klibc.h> + +#include "bochs.h" + +/* This is a special hack that is only useful when running the + operating system under the Bochs emulator. */ +#define SOS_BOCHS_IOPORT 0xe9 + +sos_ret_t sos_bochs_setup(void) +{ + return SOS_OK; +} + + +#define sos_bochs_putchar(chr) \ + outb((chr), SOS_BOCHS_IOPORT) + +sos_ret_t sos_bochs_putstring(const char* str) +{ + for ( ; str && (*str != '\0') ; str++) + sos_bochs_putchar(*str); + + return SOS_OK; +} + + +sos_ret_t sos_bochs_puthex(unsigned val, int nbytes) +{ + unsigned c; + +#define BOCHS_PRTHEX(q) \ + ({ unsigned char r; if ((q) >= 10) r='a'+(q)-10; \ + else r='0'+(q); sos_bochs_putchar(r); }) + + switch (nbytes) + { + case 4: + c = (val >> 24) & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + case 3: + c = (val >> 16) & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + case 2: + c = (val >> 8) & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + case 1: + c = val & 0xff; + BOCHS_PRTHEX((c >> 4)&0xf); + BOCHS_PRTHEX(c&0xf); + } + + return SOS_OK; +} + + +sos_ret_t sos_bochs_hexdump(const void* addr, int nbytes) +{ + int offs; + for (offs = 0 ; offs < nbytes ; offs++) + { + const unsigned char *c; + + if ((offs % 16) == 0) + { + sos_bochs_putstring("0x"); + sos_bochs_puthex(offs, 4); + } + + if ((offs % 8) == 0) + sos_bochs_putstring(" "); + + c = (const unsigned char*)(addr + offs); + sos_bochs_puthex(*c, 1); + sos_bochs_putstring(" "); + + if (((offs + 1) % 16) == 0) + sos_bochs_putstring("\n"); + } + + if (offs % 16) + sos_bochs_putstring("\n"); + + return SOS_OK; +} + + +sos_ret_t sos_bochs_printf(const char *format, /* args */...) +{ + char buff[256]; + va_list ap; + + va_start(ap, format); + vsnprintf(buff, sizeof(buff), format, ap); + va_end(ap); + + return sos_bochs_putstring(buff); +} diff --git a/sos-code-article4/drivers/bochs.h b/sos-code-article4/drivers/bochs.h new file mode 100644 index 0000000..310b023 --- /dev/null +++ b/sos-code-article4/drivers/bochs.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_BOCHS_H_ +#define _SOS_BOCHS_H_ + +/** + * @file bochs.h + * + * If you compiled Bochs with the --enable-e9-hack, then any character + * printed to the 0xE9 I/O port is printed to the xterm that is + * running Bochs. This may appear to be a detail, but in fact, this + * functionnality is *VERY* precious for debugging purposes. This + * """driver""" handles this feature. + */ + +#include <sos/errno.h> +#include <sos/types.h> + +sos_ret_t sos_bochs_setup(void); + +sos_ret_t sos_bochs_putstring(const char* str); + +/** Print the least signficant 32 (nbytes == 4), 24 (nbytes == 3), 16 + (nbytes == 2) or 8 (nbytes == 1) bits of val in hexadecimal. */ +sos_ret_t sos_bochs_puthex(unsigned val, int nbytes); + +/** hexdump-style pretty printing */ +sos_ret_t sos_bochs_hexdump(const void* addr, int nbytes); + +/** + * Print the formatted string. Very restricted version of printf(3): + * 1/ can print max 255 chars, 2/ supports only %d/%i, %c, %s, %x + * without any support for flag charachters (eg %08x). + */ +sos_ret_t sos_bochs_printf(const char *format, /* args */...) + __attribute__ ((format (printf, 1, 2))); + +#endif diff --git a/sos-code-article4/drivers/x86_videomem.c b/sos-code-article4/drivers/x86_videomem.c new file mode 100644 index 0000000..cc4b79c --- /dev/null +++ b/sos-code-article4/drivers/x86_videomem.c @@ -0,0 +1,128 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <sos/klibc.h> +#include <hwcore/ioports.h> + +#include "x86_videomem.h" + +/* The text video memory starts at address 0xB8000. Odd bytes are the + ASCII value of the character, even bytes are attribute for the + preceding character. */ +#define VIDEO 0xb8000 + + +/* Console screen size */ +#define LINES 25 +#define COLUMNS 80 + + +/** The structure of a character element in the video memory. @see + http://webster.cs.ucr.edu/AoA DOS edition chapter 23 */ +typedef struct { + unsigned char character; + unsigned char attribute; +} __attribute__ ((packed)) x86_video_mem[LINES*COLUMNS]; + + + +/** The base pointer for the video memory */ +static volatile x86_video_mem *video = (volatile x86_video_mem*)VIDEO; + +sos_ret_t sos_x86_videomem_setup(void) +{ + /* + * Hide cursor. @see Ralf Brown's interrupt (and port) list + * http://www-2.cs.cmu.edu/~ralf/files.html + */ +#define CRT_REG_INDEX 0x3d4 +#define CRT_REG_DATA 0x3d5 + + /* CRT index port => ask for access to register 0xa ("cursor + start") */ + outb(0x0a, CRT_REG_INDEX); + + /* (RBIL Tables 708 & 654) CRT Register 0xa => bit 5 = cursor OFF */ + outb(1 << 5, CRT_REG_DATA); + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_cls(unsigned char attribute) +{ + /* Clears the screen */ + int i; + for(i = 0 ; i < LINES*COLUMNS ; i++) + { + (*video)[i].character = 0; + (*video)[i].attribute = attribute; + } + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_putstring(unsigned char row, unsigned char col, + unsigned char attribute, + const char *str) +{ + unsigned video_offs = row*COLUMNS + col; + + if (video_offs >= LINES*COLUMNS) + return -SOS_EINVAL; + + for ( ; str && *str && (video_offs < LINES*COLUMNS) ; str++, video_offs++) + { + (*video)[video_offs].character = (unsigned char)*str; + (*video)[video_offs].attribute = attribute; + } + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_putchar(unsigned char row, unsigned char col, + unsigned char attribute, + unsigned char c) +{ + unsigned video_offs = row*COLUMNS + col; + + if (video_offs >= LINES*COLUMNS) + return -SOS_EINVAL; + + (*video)[video_offs].character = c; + (*video)[video_offs].attribute = attribute; + + return SOS_OK; +} + + +sos_ret_t sos_x86_videomem_printf(unsigned char row, unsigned char col, + unsigned char attribute, + const char *format, /* args */...) +{ + char buff[256]; + va_list ap; + + va_start(ap, format); + vsnprintf(buff, sizeof(buff), format, ap); + va_end(ap); + + return sos_x86_videomem_putstring(row, col, attribute, buff); +} diff --git a/sos-code-article4/drivers/x86_videomem.h b/sos-code-article4/drivers/x86_videomem.h new file mode 100644 index 0000000..31a9dfc --- /dev/null +++ b/sos-code-article4/drivers/x86_videomem.h @@ -0,0 +1,98 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_X86_VIDEOMEM_H_ +#define _SOS_X86_VIDEOMEM_H_ + +/** + * @file x86_videomem.h + * + * On x86 PC platforms, the text mode screen memory (and CGA/EGA/VGA + * too) is mapped into physical memory. This file handles access to + * this screen, supposed to be set in text-mode, through this memory + * area. All the functions below print the characters directly to the + * memory, without interpreting the escaped characters (such as \n, + * \r...) + */ + +#include <sos/errno.h> + +/** + * x86 video attributes + * See http://webster.cs.ucr.edu/AoA/DOS/ch23/CH23-1.html + */ +/* Normal and Dark/Light foreground */ +#define SOS_X86_VIDEO_FG_BLACK 0 +#define SOS_X86_VIDEO_FG_DKGRAY 8 +#define SOS_X86_VIDEO_FG_BLUE 1 +#define SOS_X86_VIDEO_FG_LTBLUE 9 +#define SOS_X86_VIDEO_FG_GREEN 2 +#define SOS_X86_VIDEO_FG_LTGREEN 10 +#define SOS_X86_VIDEO_FG_CYAN 3 +#define SOS_X86_VIDEO_FG_LTCYAN 11 +#define SOS_X86_VIDEO_FG_RED 4 +#define SOS_X86_VIDEO_FG_LTRED 12 +#define SOS_X86_VIDEO_FG_MAGENTA 5 +#define SOS_X86_VIDEO_FG_LTMAGENTA 13 +#define SOS_X86_VIDEO_FG_BROWN 6 +#define SOS_X86_VIDEO_FG_YELLOW 14 +#define SOS_X86_VIDEO_FG_LTGRAY 7 +#define SOS_X86_VIDEO_FG_WHITE 15 +/* Background */ +#define SOS_X86_VIDEO_BG_BLACK (0 << 4) +#define SOS_X86_VIDEO_BG_BLUE (1 << 4) +#define SOS_X86_VIDEO_BG_GREEN (2 << 4) +#define SOS_X86_VIDEO_BG_CYAN (3 << 4) +#define SOS_X86_VIDEO_BG_RED (4 << 4) +#define SOS_X86_VIDEO_BG_MAGENTA (5 << 4) +#define SOS_X86_VIDEO_BG_BROWN (6 << 4) +#define SOS_X86_VIDEO_BG_LTGRAY (7 << 4) +/* Blinking */ +#define SOS_X86_VIDEO_FG_BLINKING (1 << 7) + + +/** Setup the video RAM mapping and clear the screen */ +sos_ret_t sos_x86_videomem_setup(void); + +/** Clears the screen and set the background color as given by + attribute */ +sos_ret_t sos_x86_videomem_cls(unsigned char attribute); + +/** Print the string on the scren with the given attribute. Does not + handle scrolling */ +sos_ret_t sos_x86_videomem_putstring(unsigned char row, unsigned char col, + unsigned char attribute, + const char *str); + +/** Print the character on the scren with the given attribute. Does not + handle scrolling */ +sos_ret_t sos_x86_videomem_putchar(unsigned char row, unsigned char col, + unsigned char attribute, + unsigned char c); + +/** + * Print the formatted string. Very restricted version of printf(3): + * 1/ can print max 255 chars, 2/ supports only %d/%i, %c, %s, %x + * without any support for flag charachters (eg %08x). + */ +sos_ret_t sos_x86_videomem_printf(unsigned char row, unsigned char col, + unsigned char attribute, + const char *format, /* args */...) + __attribute__ ((format (printf, 4, 5))); + +#endif /* _SOS_X86_VIDEOMEM_H_ */ diff --git a/sos-code-article4/extra/Makefile b/sos-code-article4/extra/Makefile new file mode 100644 index 0000000..f858aa6 --- /dev/null +++ b/sos-code-article4/extra/Makefile @@ -0,0 +1,40 @@ +OBJCOPY=objcopy + +all: sos_qemu.img + +-include ../.mkvars + +# The image is the simple concatenation of the boot sector and the kernel +# It may be use in bochs or on a real floppy, but NOT in qemu (see below) +sos_bsect.img: bsect.bin sos.bin + cat $^ > $@ + @echo "[31mYou can use the $@ image in bochs or on a real floppy (NOT qemu)[m" + +# For qemu, the trick is to tell it we have *more* than 1440 sectors (720kB). +# Rtherwise the qemu disk geometry will be configured to be that of a 720kB +# floppy, while our boot sector assumes it to be 1.44MB +sos_qemu.img: sos_bsect.img + # Padding with 0s after the bsect/kernel image + cat $< /dev/zero | dd of=$@ bs=1k count=1440 + @echo "[31mYou can use the $@ image in qemu, bochs, or on a real floppy[m" + +# we extract the boot sector from the main ELF binary +bsect.bin: sos_bsect.elf + $(OBJCOPY) -v -O binary -j .bootsect $< $@ + +# we extract the kernel code from the main ELF binary +sos.bin: sos_bsect.elf + $(OBJCOPY) -v -O binary -R .bootsect $< $@ + +# The main ELF binary contains the boot sector and the kernel code +# linked together (hence we deal with a SINGLE image that we split +# above) because they share some symbol definitions +sos_bsect.elf: bootsect.o compile_kernel + $(LD) --warn-common -T ./sos_bsect.lds -o $@ \ + bootsect.o $(wildcard ../hwcore/*.o ../drivers/*.o ../sos/*.o) + +compile_kernel: + $(MAKE) -C .. + +clean: + $(RM) *.img *.elf *.bin *~ *.o *.out diff --git a/sos-code-article4/extra/README b/sos-code-article4/extra/README new file mode 100644 index 0000000..0272f1f --- /dev/null +++ b/sos-code-article4/extra/README @@ -0,0 +1,73 @@ + +Contents of the extra/ directory +================================ + +Data and configuration files to support generation of sos on non-x86 +and/or grub-less hosts: + - dot.mkvars: file to copy as .mkvars in the root directory to + compile on a non-x86 host, and to generate the grub floppy image on + a grub-less host + - grub.img.gz: compressed image of a Grub floppy (without any + kernel). Used by dot.mkvars. + - mtoolsrc: file needed by .mkvars to compile a the floppy image + +Support of a sos-specific boot sector: + - Makefile: rules to compile sos_bsect.img, the floppy image with the + boot sector and the Sos + - bootsect.S: x86 Sos boot sector (GNU as). Depends on sos_bsect.lds + - sos_bsect.lds: ld script to bind the boot sector with the remaining + of the kernel + +Misc: + - qemu-port-e9.diff: patch over qemu to support the bochs "port 0xe9 hack" + + +What you can do with these files +================================ + + +*** Compile SOS from another architecture: +------------------------------------------ + - compile a cross-compiler for the i586-gnu target. This involves + compiling the binutils and gcc. Here are example configuration + options for them: + binutils (replace sparc-cun-solaris with your arch): + ../binutils-2.13/configure --prefix=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/stow/binutils-2.11 --host=sparc-sun-solaris2.7 i586-gnu + make && make install + gcc (ditto): + CFLAGS="-O2 -Dinhibit_libc" ../gcc-3.2/configure --target=i586-gnu --prefix=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/stow/gcc-3.2 --with-as=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/bin/as --with-ld=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/bin/ld --with-gnu-as --with-gnu-ld --enable-languages=c --disable-shared --disable-multilib --disable-nls --enable-threads=single + make && make install + - compile the mtools + - copy dot.mkvars to the root directory of SOS, as ".mkvars" + - customize the CC/LD/... variables to suit your cross-compiler + installatioon + - now you may run make from the SOS root directory, it should + generate the Grub boot floppy image. The following warning is + normal: + .mkvars:16: attention : écrasement des commandes pour la cible « grub-sos.img » + Makefile:92: attention : anciennes commandes ignorées pour la cible « grub-sos.img » + + +*** To compile SOS from an x86 where grub is not or incorrectly installed: +-------------------------------------------------------------------------- + - copy dot.mkvars to the root directory of SOS, as ".mkvars" + - customize the CC/LD/... variables to suit your cross-compiler + installatioon + - now you may run make from the SOS root directory, it should + generate the Grub boot floppy image. The following warning is + normal: + .mkvars:16: attention : écrasement des commandes pour la cible « grub-sos.img » + Makefile:92: attention : anciennes commandes ignorées pour la cible « grub-sos.img » + + +*** To compile SOS with its own bootloader: +------------------------------------------- + - for cross-architecture compilation: see above + - cd to this extra/ directory + - run 'make' + - the floppy image is: sos_bsect.img + NOTE : SOS will not boot correctly this way after article 2 ! + + +-- +David Decotigny diff --git a/sos-code-article4/extra/bootsect.S b/sos-code-article4/extra/bootsect.S new file mode 100644 index 0000000..f01ca20 --- /dev/null +++ b/sos-code-article4/extra/bootsect.S @@ -0,0 +1,393 @@ + +/* + * @(#) $Id: bootsect.S,v 1.6 2004/06/18 07:43:51 d2 Exp $ + * Description : Bootsecteur en syntaxe AT&T + * Auteurs : Thomas Petazzoni & Fabrice Gautier & Emmanuel Marty + * Jerome Petazzoni & Bernard Cassagne & coffeeman + * David Decotigny + * Bug reports to kos-misc@enix.org + */ + +/* + * But global de ce bootsecteur : + * + * - Initialiser la becane + * - Charger le kernel + * - Passer en mode protege + * - Executer le kernel + * + * Taille restante : Je vous rappelle qu'un bootsecteur ne peut faire + * qu'au maximum 512 octets dont 2 octets obligatoires 0xAA55. Sur + * les 510 octets reellement utilisables, il reste 3 octets dispo (60 + * si on decide d'enlever le BPB un jour) !!! + * + * thomas_petazzoni : - detection des codes d'erreurs de chargement + * David_Decotigny : - Passage en GNU as + * David_Decotigny : - Chargement du noyau au-dela du 1er Mega (taille + * max = 0x9e000 octets = 632ko), pour avoir le + * meme noyau sous grub et avec le bootsecteur + */ + + /* + * Sequence d'operations : + * - Le BIOS charge le bootsect en 0x7c00 (BOOT_ADRESS). On choisit + * la representation 0x7c0:0000 pour que le .org 0 reste valide + * - Le bootsect se deplace de lui-meme en 0x9f000 (COPY_ADRESS). On + * choisit la representation 0x9f00:0000 pour que le .org 0 reste + * valide + * - Le bootsect verifie que le processeur est du type 386+ + * - Il charge le noyau depuis la disquette en memoire a partir de + * 0x1000 (LOAD_ADRESS). Le noyau peut au max tenir sur + * SECTORS_TO_LOAD secteurs + * - Il passe en pmode flat (apres ouverture a20) + * - Il recopie le noyau (situe en LOAD_ADRESS) vers son adresse + * finale (FINAL_ADDRESS = 2Mo). La recopie se fait sur tout l'espace + * LOAD_ADRESS ---> COPY_ADRESS, c'est a dire sur 0x9e000 octets = + * 632ko. Le noyau peut donc au max faire 632ko. Le nombre max de + * secteurs de disquette qu'on peut charger est donc 1264 + */ + + +/* La taille de la pile */ +#define BOOT_STACK_SIZE 0x4000 + + .file "bootsect.S" + + /* Tout est place dans une seule section */ + .section ".bootsect" + + /* L'essentiel du bootsector (sauf les 1eres instructions) + sont a un offset 0. On fait en sorte que le compilo soit + d'accord la-dessus. Quand on a des adresse realm exotiques + (0x7c00, 0x9f000, ...), on s'arrange toujours pour avoir un + offset de 0 => on choisira le segment adapte (0x7c0, + 0x9f00, ...). Il ne faut pas oublier le ld -Ttext 0 */ + .org 0 + + /* Pour que gas genere du 16bits, afin que ca marche en realm */ + .code16 + +#define SECTORS_TO_LOAD 128 /* 64 ko */ /* MAX=1264 */ + +/* + * Parametres de la disquette. Comme c'est chiant de faire une + * procedure de detection auto, et que ca prend de la place, on fait + * ca "a la main". Par exemple, une DD 720 Ko a 9 secteurs/piste, une + * 1.44 Mo a 18 secteurs/pistes + */ +#define CYLS 80 +#define HEADS 1 +#define SECTS 18 + +#define BOOT_ADRESS 0x07C00 /* Adresse de demarrage (lineaire) */ +#define BOOT_SEG (BOOT_ADRESS>>4) /* Segment de Boot */ +#define BOOT_SIZE 512 /* Taille bu bootsecteur */ +#define COPY_ADRESS 0x9F000 /* La ou on va copier le + bootsecteur (lineaire) */ +#define COPY_SEG (COPY_ADRESS>>4) /* Segment de la ou on va + copier le bootsecteur */ +#define LOAD_ADRESS 0x01000 /* 1er chargement du systeme */ +#define LOAD_SEG (LOAD_ADRESS>>4) /* Segment du 1er chargement du */ +#define MAX_KERN_LEN COPY_ADRESS-LOAD_ADRESS /* Taille noyau maxi */ + +/* IMPORTANT : Cette valeur DOIT etre identique a l'adresse presente + dans sos.lds ! */ +#define FINAL_ADDRESS 0x200000 /* Adresse finale (physique de 0 a 4G) + ou est charge le noyau */ + +#define OP16 .byte 0x66 ; +#define OP32 .byte 0x66 ; + +/* + * Procedure qui vide le buffer clavier. + */ +#define WAITKB \ + 1: ;\ + .word 0xeb ;\ + .word 0xeb ;\ + inb $0x64, %al ;\ + andb $0x2, %al ;\ + jnz 1b + + /* Le point d'entree dans le bootsect */ +.globl _bsect +_bsect: + + /* + * La portion qui suit est situee a un offset 0x7c00 en + * memoire. Attention donc aux references memoire dans cette + * partie. On choisit de rester en offset 0 (.org 0), mais on + * charge correctement les segments a 0x7c0. + */ + + movw $BOOT_SEG, %ax /* le bootsecteur est a 0x7C00 en lineaire */ + movw %ax, %ds /* on le copie a l'adresse COPY_ADRESS */ + xorw %si, %si /* comme cette adresse est la plus haute de la mem */ + xorw %di, %di /* on pourra charger un kernel + gros */ + movw $(BOOT_SIZE>>1), %cx + movw $COPY_SEG, %ax + movw %ax, %es + cld + rep ; movsw + + /* on continue a executer le bootsecteur, mais maintenant a + partir de 0x9F000, qu'on represente sous la forme + 0x9f00:offset */ + ljmp $COPY_SEG, $here + + /* + * A partir de maintenant, on est a un offset 0 en memoire + * (segment 0x9f00), conformement a ce que veut le compilo. + */ +here: + movw %ax, %ds + + /* Petite pile temporaire (1k - 3.84k en RAM ; les adresses 0-1k + correspondent au vecteur d'interruptions). */ + movw %ax, %ss + movw $(LOAD_ADRESS - 0x10), %sp + + /* Efface l'ecran */ + movb $0x0, %ah + movb $0x3, %al + int $0x10 + + /* Affiche les messages d'attente */ + movw $loadkern, %si + call message + movw $check, %si + call message + +check386: + /* + * la attention, plus complexe : on teste si le proc est un + * 386+ pour cela, on va essayer de modifier les bits 12 ? 14 + * du registre E-flag si la modification reste, alors le proc + * est un 386+, sinon, c'est =< 286 + * + * Merci a Emmanuel Marty pour la compatibilite avec les 386 + * "pre-jurassique" + */ + + pushf /* on sauvegarde le E-Flag */ + movb $0x70, %ah + pushw %ax + popf + pushf + popw %ax + orb %ah, %ah + je no386 /* si la modif n'est pas valable, alors on saute a + no386 */ + popf /* on les restaure ? la fin ... */ + + /* Message de confirmation de 386+ et d'attente */ + movw $found386, %si + call message + movw $loading, %si + call message + +/* Copie du noyau disquette => RAM a partir de 0x1000 + L'adresse de destination est définie par es:0, où es vaut + initialement 0x100 (ie correspond alors à l'adresse 256*16, soit 4 + ko). Chaque itération incrémente ce registre es de 32, ce qui + correspond à un bond de 32*16 en mémoire, soit la taille d'un + secteur. De cette façon, puisqu'on joue sur les segments plutôt que + sur les offsets, la taille du noyau n'est pas limitée à 64 ko. Elle + est limitée par contre à la taille de la mémoire disponible sous + les 1Mo, \ie 640 ko (0x9f000 - 0x1000). */ +copyKernel: + /* Chargement du noyau en LOAD_SEG:0 */ + /* 3 iterateurs : + - load_size : le nbre de secteurs a charger + - cl : le secteur ou on en est pour le + cylindre en cours (<= SECTS) + - dh : la tete en cours (0/1) + */ + movb $0, %dl + movw $LOAD_SEG, %ax + movw %ax, %es + + xorw %bx, %bx + xorw %dx, %dx + movw $1, %cx /* premier secteur */ + +.nextsector: /* prochain secteur */ + incb %cl /* en incrementant CL */ + cmpb $SECTS, %cl /* si CL =< SECTS (=nbre de secteurs/pistes) + alors on charge */ + jbe .sector + movb $1, %cl /* sinon on revient au secteur 1 */ + incb %dh /* mais sur l'autre tete */ + cmpb $1, %dh /* on recompare, si DH =< 1 */ + je .sector /* on charge */ + movb $0, %dh /* sinon on repasse a la tete 0 */ + incb %ch /* mais on change de cylindre */ + +.sector: + pushw %es + movw $0x0201, %ax /* service 0x2, chargement 0x1 seecteur */ + int $0x13 /* Go ! */ + jc halt /* erreur */ + popw %ax + addw $32, %ax /* on a charge un secteur, donc on doit + charger 512 bytes plus loin */ + movw %ax, %es /* on avance donc le segment du buffer de + 32bytes, ie 1 secteur en RAM (car 32*16=512) */ + + movw $(0x0E*256+'.'), %ax /* affiche un point */ + int $0x10 + + decw (load_size) /* et on repart pour le prochain secteur + tant qu'on n'a pas fini ! */ + jnz .nextsector + +after: + movw $0x03f2, %dx + inb %dx, %al /* stoppe le moteur */ + andb $0x0f, %al + outb %al, %dx + + cli /* on interdit les interruptions */ + +fincopie: + pushw %cs + popw %ds + + /* on ouvre la porte A20 */ + WAITKB /* on vide le buffer */ + movb $0xd1, %al /* on met a jour le port */ + outb %al, $0x64 + WAITKB + movb $0xdf, %al /* bit 2 = ouverture/fermeture */ + outb %al, $0x60 + + /* + * init gdt + */ +InitGDT: + /* Préparation du flat mode */ + lgdt gdtr + +GoPMode: + /* Passage en mode protégé */ + movl %cr0, %eax + orb $1, %al /* set PE bit to 1 */ + movl %eax, %cr0 + + /* we are not yet in Pmode jump 'in' pmode clearing prefetch + * queue and loading a new selector */ + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + +/* + * Code 32 bits ============================================================ + */ + .code32 + +JumpToHere32: /* Se deplace a l'endroit actuel, en passant en 32bits + et en utilisant la gdt, et vide la prefetch queue */ + .byte 0x66 /* Prefixe 32bits : en realite, jusqu'au jmp, on est + encore en 16 bits */ + ljmp $0x8, $(COPY_ADRESS+(Here32)) +Here32: + /* Et voila : On est en 32 bits vrai */ + +MoveKernelToFinalAddr: /* Deplace le noyau (en LOAD_ADDRESS) vers sa + destination finale (FINAL_ADDRESS) */ + movl $0x10, %eax + movl %eax, %ds /* Seg Src = DSeg */ + movl %eax, %es /* Sed Dest = DSeg */ + cld + movl $LOAD_ADRESS, %esi /* On commence la copie au debut du noyau */ + movl $FINAL_ADDRESS, %edi /* On copie vers cette adresse */ + movl $MAX_KERN_LEN, %ecx /* Taille recopie */ + shrl $2, %ecx + rep + movsl + +LaunchKernel: + /* Met en place une pile au niveau du symbole "stack" */ + movl %eax, %ss + movl $(stack + BOOT_STACK_SIZE), %ebp + movl %ebp, %esp + + /* Saut vers le noyau. La GDT est en place (flat mode), les + * selecteurs aussi, a20 est ouverte, et les interruptions sont + * cli + pas de idt. Le PIC n'est pas programme */ + ljmp $0x8, $sos_main + +/* + * Utilities ============================================================ + */ + .code16 + +message: + lodsb /* charge ds:si dans al et incremente si */ + orb %al, %al /* si al = 0 */ + jz 1f + movb $0x0e, %ah /* service 0Eh (affichage d'un caractere) */ + movw $0x0007, %bx /* Parametres : blanc sur fond noir */ + int $0x10 /* Appel de l'interruption 10h */ + jmp message /* On repart au début ... */ + 1: ret /* si la chaine est finie alors on retourne + dans la fonction appelante */ + +halt: + pushw %cs + popw %es + movw $haltmsg, %si + call message + cli + 1: jmp 1b + ret + +no386: + movw $need386, %si + call message + call halt + + /* + * GDT + */ + +gdt: +gdtr: +NULL_Desc: + .word (EndGDT)-(gdt)-1 /* Taille GDT */ + .long (gdt)+COPY_ADRESS +unused: + .word 0 + +CS_Desc: /* 0x8 */ + .word 0xFFFF, 0 + .byte 0, 0x9B, 0xCF, 0 + +DS_Desc: /* 0x10 */ + .word 0xFFFF, 0 + .byte 0, 0x93, 0xCF, 0 + +EndGDT: + + /* quelques messages */ + +loadkern: .string "-= S O S =- : The Simple Operating System \r\n" +check: .string "Checking for a 386+ processor... " +found386: .string " [OK]\r\n" +need386: .string " [FAILED]\r\n" +diskerror: .string "Disk Error\r\n" +loading: .string "Loading... " +haltmsg: .string "System Halted\r\n" + +/*** Les code/données du boot secteur se terminent ICI. le marqueur de + * fin (aa55) est ajouté automatiquement par le script ld + * sos_bsect.lds ***/ + +/* La pile de 16k qu'on utilise au niveau de LaunchKernel se trouve + declaree avec le noyau, dans sa section ".bss", cad HORS du boot + secteur ! (sinon ca depasserait 512B, forcément). On aurait pu la + définir directement dans le sos_bsect.lds, ou dans un fichier .c + auxiliaire pour plus de clarté */ +.comm stack, BOOT_STACK_SIZE diff --git a/sos-code-article4/extra/dot.mkvars b/sos-code-article4/extra/dot.mkvars new file mode 100644 index 0000000..1f7dca5 --- /dev/null +++ b/sos-code-article4/extra/dot.mkvars @@ -0,0 +1,29 @@ +# For cross-compilation and/or installations without grub available, +# copy this file as .mkvars to the root directory of the SOS sources, +# and customize the CC/LD/... variables. You still need the mtools +# installed and running + +CC := i586-gnu-gcc +LD := i586-gnu-ld +OBJCOPY := i586-gnu-objcopy +CFLAGS += -O3 + +# Configuration of mtools +MTOOLSRC = extra/mtoolsrc +export MTOOLSRC + +$(MULTIBOOT_IMAGE): $(KERNEL_OBJ) menu.txt + gzip -dc < extra/grub.img.gz > $@ + mcopy menu.txt v:/boot/grub/ + mmd v:/system + mcopy sos.elf v:/system/sos.elf + +menu.txt: + echo timeout 0 > $@ + echo default 0 >> $@ + echo title SOS >> $@ + echo "root (fd0)" >> $@ + echo kernel /system/sos.elf >> $@ + +runbochs: all + echo c | bochs -q diff --git a/sos-code-article4/extra/grub.img.gz b/sos-code-article4/extra/grub.img.gz Binary files differnew file mode 100644 index 0000000..4f98e74 --- /dev/null +++ b/sos-code-article4/extra/grub.img.gz diff --git a/sos-code-article4/extra/mtoolsrc b/sos-code-article4/extra/mtoolsrc new file mode 100644 index 0000000..df1a26e --- /dev/null +++ b/sos-code-article4/extra/mtoolsrc @@ -0,0 +1,2 @@ +# For older versions of mtools, you may have to remove "filter" +drive v: file="fd.img" 1.44M filter diff --git a/sos-code-article4/extra/qemu-port-e9.diff b/sos-code-article4/extra/qemu-port-e9.diff new file mode 100644 index 0000000..d8be044 --- /dev/null +++ b/sos-code-article4/extra/qemu-port-e9.diff @@ -0,0 +1,73 @@ +--- Makefile.target 17 Mar 2004 23:46:04 -0000 1.19 ++++ Makefile.target 18 Mar 2004 14:20:29 -0000 +@@ -217,7 +217,8 @@ + # must use static linking to avoid leaving stuff in virtual address space + VL_OBJS=vl.o osdep.o block.o monitor.o \ + ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ +- fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o ++ fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o \ ++ port-e9.o + ifeq ($(TARGET_ARCH), ppc) + VL_OBJS+= hw.o + endif +--- hw/pc.c 14 Mar 2004 21:46:48 -0000 1.2 ++++ hw/pc.c 18 Mar 2004 14:20:29 -0000 +@@ -371,6 +371,7 @@ + SB16_init(); + + fdctrl_init(6, 2, 0, 0x3f0, fd_table); ++ port_e9_init(); + + cmos_init(ram_size, boot_device); + } +--- /dev/null 2003-01-30 11:24:37.000000000 +0100 ++++ port-e9.c 2004-03-18 15:18:52.660493187 +0100 +@@ -0,0 +1,38 @@ ++/* ++ * QEMU Port 0xe9 hack ++ * ++ * Copyright (c) 2000-2004 E. Marty, the bochs team, D. Decotigny ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++#include <stdio.h> ++#include <unistd.h> ++#include <inttypes.h> ++ ++#include "vl.h" ++ ++static void bochs_e9_write(void *opaque, uint32_t address, uint32_t data) ++{ ++ write(fileno(stdout), &data, 1); ++} ++ ++void port_e9_init () ++{ ++ register_ioport_write(0xe9, 1, 1, bochs_e9_write, NULL); ++} +--- vl.h 17 Mar 2004 23:17:16 -0000 1.14 ++++ vl.h 18 Mar 2004 14:29:06 -0000 +@@ -268,4 +268,7 @@ + void term_flush(void); + void term_print_help(void); + ++/* port-e9.c */ ++void port_e9_init(void); ++ + #endif /* VL_H */ diff --git a/sos-code-article4/extra/sos_bsect.lds b/sos-code-article4/extra/sos_bsect.lds new file mode 100644 index 0000000..ac42f23 --- /dev/null +++ b/sos-code-article4/extra/sos_bsect.lds @@ -0,0 +1,61 @@ +/* Copyright (C) 2004, David Decotigny + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +SECTIONS +{ + /* *********************************************** + * The bootsector is here. We link it against the remaining of the kernel + * in order to automatically figure out its size that must be loaded + * from file to memory (see the load_size definition below) + */ + + /* If we use one, we put the boot sector here. We don't set its + * address to 0x7c000 (aka 0x7c00:0), since it reloads itself to + * 0x9f000, causing the 0x7c000 address to be meaningless too. So we + * chose to pretend that the address is 0x0, and to make a little + * address arithmetic in bootsect.S */ + .bootsect 0x0 : + { + /* The code for the boot sector goes here */ + *(.bootsect); + + /* The load_size symbol contains the size of the area (in + * sectors, aka 512 Bytes) that the boot sector should copy from + * the disk. The bss section is not included since it uses 0 + * bytes on disk */ + load_size = .; + LONG((__e_load - __b_load + 511) >> 9); + /* ---> This is equivalent to ceil( (__e_load - __b_load) / 512 ) */ + + /* At offsets 511 and 512, we set the boot sector signature (AA55h) */ + . = 0x1fe; + SHORT(0xAA55); + } +} + + +/* This is to avoid a cut/paste here. Please notice that a multiboot + * section WILL be inserted, which is NOT mandatory (we could have + * removed it without getting into trouble). Please note however that + * the *.bin files will NOT be multiboot compatible (they are not in ELF + * format): they are expected to be directly booted by the BIOS (or + * by the "chainloader" command of Grub). */ +INCLUDE ../support/sos.lds + +/* We overload the entry set in sos.lds, just to avoid an ld warning */ +ENTRY(sos_main); diff --git a/sos-code-article4/hwcore/exception.c b/sos-code-article4/hwcore/exception.c new file mode 100644 index 0000000..9ab5aff --- /dev/null +++ b/sos-code-article4/hwcore/exception.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "idt.h" +#include "irq.h" + +#include "exception.h" + +/* array of exception wrappers, defined in exception_wrappers.S */ +extern sos_vaddr_t sos_exception_wrapper_array[SOS_EXCEPT_NUM]; + +/* arrays of exception handlers, shared with exception_wrappers.S */ +sos_exception_handler_t sos_exception_handler_array[SOS_EXCEPT_NUM] = + { NULL, }; + +sos_ret_t sos_exceptions_setup(void) +{ + /* We inidicate that the double fault exception handler is defined, + and give its address. this handler is a do-nothing handler (see + exception_wrappers.S), and it can NOT be overriden by the + functions below */ + return sos_idt_set_handler(SOS_EXCEPT_BASE + SOS_EXCEPT_DOUBLE_FAULT, + (sos_vaddr_t) sos_exception_wrapper_array[SOS_EXCEPT_DOUBLE_FAULT], + 0 /* CPL0 routine */); +} + + +sos_ret_t sos_exception_set_routine(int exception_number, + sos_exception_handler_t routine) +{ + sos_ret_t retval; + sos_ui32_t flags; + + if ((exception_number < 0) || (exception_number >= SOS_EXCEPT_NUM)) + return -SOS_EINVAL; + + /* Double fault not supported */ + if (exception_number == SOS_EXCEPT_DOUBLE_FAULT) + return -SOS_ENOSUP; + + sos_disable_IRQs(flags); + + retval = SOS_OK; + + /* Set the exception routine to be called by the exception wrapper */ + sos_exception_handler_array[exception_number] = routine; + + /* If the exception is to be enabled, update the IDT with the exception + wrapper */ + if (routine != NULL) + retval + = sos_idt_set_handler(SOS_EXCEPT_BASE + exception_number, + (sos_vaddr_t) sos_exception_wrapper_array[exception_number], + 0 /* CPL0 routine */); + else /* Disable the IDT entry */ + retval + = sos_idt_set_handler(SOS_EXCEPT_BASE + exception_number, + (sos_vaddr_t)NULL /* No routine => disable IDTE */, + 0 /* don't care */); + + sos_restore_IRQs(flags); + return retval; +} + + +sos_exception_handler_t sos_exception_get_routine(int exception_number) +{ + if ((exception_number < 0) || (exception_number >= SOS_EXCEPT_NUM)) + return NULL; + + /* Double fault not supported */ + if (exception_number == SOS_EXCEPT_DOUBLE_FAULT) + return NULL; + + /* Expected to be atomic */ + return sos_exception_handler_array[exception_number]; +} diff --git a/sos-code-article4/hwcore/exception.h b/sos-code-article4/hwcore/exception.h new file mode 100644 index 0000000..7e52fe5 --- /dev/null +++ b/sos-code-article4/hwcore/exception.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_HWEXCEPT_H_ +#define _SOS_HWEXCEPT_H_ + +/** + * @file exception.c + * + * Hardware exception routines management. + */ + +#ifndef ASM_SOURCE +# include <sos/errno.h> +#endif + +/** + * Standard Intel x86 exceptions. + * + * @see Intel x86 doc vol 3, section 5.12. + */ +#define SOS_EXCEPT_DIVIDE_ERROR 0 // No error code +#define SOS_EXCEPT_DEBUG 1 // No error code +#define SOS_EXCEPT_NMI_INTERRUPT 2 // No error code +#define SOS_EXCEPT_BREAKPOINT 3 // No error code +#define SOS_EXCEPT_OVERFLOW 4 // No error code +#define SOS_EXCEPT_BOUND_RANGE_EXCEDEED 5 // No error code +#define SOS_EXCEPT_INVALID_OPCODE 6 // No error code +#define SOS_EXCEPT_DEVICE_NOT_AVAILABLE 7 // No error code +#define SOS_EXCEPT_DOUBLE_FAULT 8 // Yes (Zero) +#define SOS_EXCEPT_COPROCESSOR_SEGMENT_OVERRUN 9 // No error code +#define SOS_EXCEPT_INVALID_TSS 10 // Yes +#define SOS_EXCEPT_SEGMENT_NOT_PRESENT 11 // Yes +#define SOS_EXCEPT_STACK_SEGMENT_FAULT 12 // Yes +#define SOS_EXCEPT_GENERAL_PROTECTION 13 // Yes +#define SOS_EXCEPT_PAGE_FAULT 14 // Yes +#define SOS_EXCEPT_INTEL_RESERVED_1 15 // No +#define SOS_EXCEPT_FLOATING_POINT_ERROR 16 // No +#define SOS_EXCEPT_ALIGNEMENT_CHECK 17 // Yes (Zero) +#define SOS_EXCEPT_MACHINE_CHECK 18 // No +#define SOS_EXCEPT_INTEL_RESERVED_2 19 // No +#define SOS_EXCEPT_INTEL_RESERVED_3 20 // No +#define SOS_EXCEPT_INTEL_RESERVED_4 21 // No +#define SOS_EXCEPT_INTEL_RESERVED_5 22 // No +#define SOS_EXCEPT_INTEL_RESERVED_6 23 // No +#define SOS_EXCEPT_INTEL_RESERVED_7 24 // No +#define SOS_EXCEPT_INTEL_RESERVED_8 25 // No +#define SOS_EXCEPT_INTEL_RESERVED_9 26 // No +#define SOS_EXCEPT_INTEL_RESERVED_10 27 // No +#define SOS_EXCEPT_INTEL_RESERVED_11 28 // No +#define SOS_EXCEPT_INTEL_RESERVED_12 29 // No +#define SOS_EXCEPT_INTEL_RESERVED_13 30 // No +#define SOS_EXCEPT_INTEL_RESERVED_14 31 // No + +#ifndef ASM_SOURCE + +typedef void (*sos_exception_handler_t)(int exception_number); + +sos_ret_t sos_exceptions_setup(void); +sos_ret_t sos_exception_set_routine(int exception_number, + sos_exception_handler_t routine); +sos_exception_handler_t sos_exception_get_routine(int exception_number); +#endif /* ! ASM_SOURCE */ + +#endif /* _SOS_HWEXCEPT_H_ */ diff --git a/sos-code-article4/hwcore/exception_wrappers.S b/sos-code-article4/hwcore/exception_wrappers.S new file mode 100644 index 0000000..2f7665c --- /dev/null +++ b/sos-code-article4/hwcore/exception_wrappers.S @@ -0,0 +1,197 @@ +/* Copyright (C) 2004 The KOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "exception.h" + +.file "exception_wrappers.S" + +.text + +/* The address of the table of handlers (defined in exception.c) */ +.extern sos_exception_handler_array + +/* The address of the table of wrappers (defined below, and shared + with exception.c */ +.globl sos_exception_wrapper_array + + +/** + * For exceptions with/without error code, refer to Intel x86 doc vol 3, + * section 5.12 + */ + +/* These wrappers are for exceptions without error code */ +.irp id, \ + SOS_EXCEPT_DIVIDE_ERROR, \ + SOS_EXCEPT_DEBUG, \ + SOS_EXCEPT_NMI_INTERRUPT, \ + SOS_EXCEPT_BREAKPOINT, \ + SOS_EXCEPT_OVERFLOW, \ + SOS_EXCEPT_BOUND_RANGE_EXCEDEED, \ + SOS_EXCEPT_INVALID_OPCODE, \ + SOS_EXCEPT_DEVICE_NOT_AVAILABLE, \ + SOS_EXCEPT_COPROCESSOR_SEGMENT_OVERRUN, \ + SOS_EXCEPT_INTEL_RESERVED_1, \ + SOS_EXCEPT_FLOATING_POINT_ERROR, \ + SOS_EXCEPT_MACHINE_CHECK, \ + SOS_EXCEPT_INTEL_RESERVED_2, \ + SOS_EXCEPT_INTEL_RESERVED_3, \ + SOS_EXCEPT_INTEL_RESERVED_4, \ + SOS_EXCEPT_INTEL_RESERVED_5, \ + SOS_EXCEPT_INTEL_RESERVED_6, \ + SOS_EXCEPT_INTEL_RESERVED_7, \ + SOS_EXCEPT_INTEL_RESERVED_8, \ + SOS_EXCEPT_INTEL_RESERVED_9, \ + SOS_EXCEPT_INTEL_RESERVED_10, \ + SOS_EXCEPT_INTEL_RESERVED_11, \ + SOS_EXCEPT_INTEL_RESERVED_12, \ + SOS_EXCEPT_INTEL_RESERVED_13, \ + SOS_EXCEPT_INTEL_RESERVED_14 + + .p2align 2, 0x90 + sos_exception_wrapper_\id: + .type sos_exception_wrapper_\id,@function + + /* Fake error code */ + pushl $0 + /* Backup the context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Call the handler with exception number as + * argument */ + pushl $\id + leal sos_exception_handler_array,%edi + call *\id*4(%edi) + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + + popl %ebp + /* Remove fake error code */ + addl $4, %esp + iret +.endr + + /* These wrappers are for exceptions with error code */ +.irp id, \ + SOS_EXCEPT_INVALID_TSS, \ + SOS_EXCEPT_SEGMENT_NOT_PRESENT, \ + SOS_EXCEPT_STACK_SEGMENT_FAULT, \ + SOS_EXCEPT_GENERAL_PROTECTION, \ + SOS_EXCEPT_PAGE_FAULT, \ + SOS_EXCEPT_ALIGNEMENT_CHECK + + .p2align 2, 0x90 + sos_exception_wrapper_\id: + .type sos_exception_wrapper_\id,@function + + /* ret eflags */ + /* ret cs */ + /* ret eip */ + /* Error code */ + + /* Backup the context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Call the handler with exception number as + * argument */ + pushl $\id + leal sos_exception_handler_array,%edi + call *\id*4(%edi) + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + + /* Error code isn't compatible with iretd */ + addl $4, %esp + + iret +.endr + + +/* Double fault handler not supported. We must define it since we + define an entry for it in the sos_exception_wrapper_array. */ +.irp id, SOS_EXCEPT_DOUBLE_FAULT +.p2align 2, 0x90 +sos_exception_wrapper_\id: +.type sos_exception_wrapper_\id,@function +1: hlt + jmp 1b /* Machine halting */ +.endr + +/* Build the sos_irq_wrapper_array, shared with interrupt.c */ +.section ".rodata" +.p2align 5, 0x0 +sos_exception_wrapper_array: + .irp id, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, \ + 16,17,18,19,20,21,22,23,24,25,26,27,29,30,31 + .long (sos_exception_wrapper_\id) + .endr diff --git a/sos-code-article4/hwcore/gdt.c b/sos-code-article4/hwcore/gdt.c new file mode 100644 index 0000000..7945c8c --- /dev/null +++ b/sos-code-article4/hwcore/gdt.c @@ -0,0 +1,150 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "segment.h" + +#include "gdt.h" + + +/** + * The sructure of a segment descriptor. + * + * @see Intel x86 doc, Vol 3, section 3.4.3, figure 3-8. For segment + * types, see section 3.5 + */ +struct x86_segment_descriptor +{ + /* Lowest dword */ + sos_ui16_t limit_15_0; /* Segment limit, bits 15..0 */ + sos_ui16_t base_paged_addr_15_0; /* Base address, bits 15..0 */ + + /* Highest dword */ + sos_ui8_t base_paged_addr_23_16; /* Base address bits 23..16 */ + sos_ui8_t segment_type:4; /* Section 3.4.3.1 (code/data) + and 3.5 (system) of Intel x86 vol 3 */ + sos_ui8_t descriptor_type:1; /* 0=system, 1=Code/Data */ + sos_ui8_t dpl:2; + sos_ui8_t present:1; + + sos_ui8_t limit_19_16:4; /* Segment limit, bits 19..16 */ + sos_ui8_t custom:1; + sos_ui8_t zero:1; + sos_ui8_t op_size:1; /* 0=16bits instructions, 1=32bits */ + sos_ui8_t granularity:1; /* 0=limit in bytes, 1=limit in pages */ + + sos_ui8_t base_paged_addr_31_24; /* Base address bits 31..24 */ +} __attribute__ ((packed, aligned (8))); + + +/** + * The GDT register, which stores the address and size of the + * GDT. + * + * @see Intel x86 doc vol 3, section 2.4, figure 2-4; and section + * 3.5.1 + */ +struct x86_gdt_register { + /* The maximum GDT offset allowed to access an entry in the GDT */ + sos_ui16_t limit; + + /* This is not exactly a "virtual" address, ie an adddress such as + those of instructions and data; this is a "linear" address, ie an + address in the paged memory. However, in SOS we configure the + segmented memory as a "flat" space: the 0-4GB segment-based (ie + "virtual") addresses directly map to the 0-4GB paged memory (ie + "linear"), so that the "linear" addresses are numerically equal + to the "virtual" addresses: this base_addr will thus be the same + as the address of the gdt array */ + sos_ui32_t base_addr; +} __attribute__((packed, aligned(8))); + + +/** + * Helper macro that builds a Segment descriptor for the virtual + * 0..4GB addresses to be mapped to the linear 0..4GB linear + * addresses. + */ +#define BUILD_GDTE(descr_privilege_level,is_code) \ + ((struct x86_segment_descriptor) { \ + .limit_15_0= 0xffff, \ + .base_paged_addr_15_0= 0, \ + .base_paged_addr_23_16= 0, \ + .segment_type= ((is_code)?0xb:0x3), \ + /* With descriptor_type (below) = 1 (code/data), \ + * see Figure 3-1 of section 3.4.3.1 in Intel \ + * x86 vol 3: \ + * - Code (bit 3 = 1): \ + * bit 0: 1=Accessed \ + * bit 1: 1=Readable \ + * bit 2: 0=Non-Conforming \ + * - Data (bit 3 = 0): \ + * bit 0: 1=Accessed \ + * bit 1: 1=Writable \ + * bit 2: 0=Expand up (stack-related) \ + * For Conforming/non conforming segments, see \ + * Intel x86 Vol 3 section 4.8.1.1 \ + */ \ + .descriptor_type= 1, /* 1=Code/Data */ \ + .dpl= ((descr_privilege_level) & 0x3), \ + .present= 1, \ + .limit_19_16= 0xf, \ + .custom= 0, \ + .op_size= 1, /* 32 bits instr/data */ \ + .granularity= 1 /* limit is in 4kB Pages */ \ + }) + + +/** The actual GDT */ +static struct x86_segment_descriptor gdt[] = { + [SOS_SEG_NULL] = (struct x86_segment_descriptor){ 0, }, + [SOS_SEG_KCODE] = BUILD_GDTE(0, 1), + [SOS_SEG_KDATA] = BUILD_GDTE(0, 0), +}; + +sos_ret_t sos_gdt_setup(void) +{ + struct x86_gdt_register gdtr; + + /* Address of the GDT */ + gdtr.base_addr = (sos_ui32_t) gdt; + + /* The limit is the maximum offset in bytes from the base address of + the GDT */ + gdtr.limit = sizeof(gdt) - 1; + + /* Commit the GDT into the CPU, and update the segment + registers. The CS register may only be updated with a long jump + to an absolute address in the given segment (see Intel x86 doc + vol 3, section 4.8.1). */ + asm volatile ("lgdt %0 \n\ + ljmp %1,$1f \n\ + 1: \n\ + movw %2, %%ax \n\ + movw %%ax, %%ss \n\ + movw %%ax, %%ds \n\ + movw %%ax, %%es \n\ + movw %%ax, %%fs \n\ + movw %%ax, %%gs" + : + :"m"(gdtr), + "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE)), + "i"(SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA)) + :"memory","eax"); + + return SOS_OK; +} diff --git a/sos-code-article4/hwcore/gdt.h b/sos-code-article4/hwcore/gdt.h new file mode 100644 index 0000000..b7e3f4c --- /dev/null +++ b/sos-code-article4/hwcore/gdt.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_GDT_H_ +#define _SOS_GDT_H_ + +/** + * @file gdt.h + * + * The routines that manage the GDT, the table that maps the virtual + * addresses (data/instructions, segment-relative), to "linear" + * addresses (ie paged-memory). In SOS/x86, we use a "flat" virtual + * space, ie the virtual and linear spaces are equivalent. + * + * @see Intel x86 doc vol 3, chapter 3 + */ + +#include <sos/errno.h> + +/** + * Configure the virtual space as a direct mapping to the linear + * address space (ie "flat" virtual space). + */ +sos_ret_t sos_gdt_setup(void); + +#endif /* _SOS_GDT_H_ */ diff --git a/sos-code-article4/hwcore/i8254.c b/sos-code-article4/hwcore/i8254.c new file mode 100644 index 0000000..5fbb156 --- /dev/null +++ b/sos-code-article4/hwcore/i8254.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2004 The KOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <hwcore/ioports.h> + +#include "i8254.h" + +/** 82c54 clock frequency */ +#define I8254_MAX_FREQ 1193180 + +/* Ports to communicate with the 82c54 */ +#define I8254_TIMER0 0x40 +#define I8254_TIMER1 0x41 +#define I8254_TIMER2 0x42 +#define I8254_CONTROL 0x43 + +/** + * Configure the first timer of the 82c54 chip as a rate generator, + * which will raise an IRQ0 on a regular periodic basis, as given by + * the freq parameter. Second (RAM refresh) and third (speaker) timers + * are left unchanged. Maximum frequency is that of the 8254 clock, ie + * 1193180 Hz. + * + * Ahhh PC systems are nice toys: this maximum "strange" frequency + * equals that of the NTSC clock (14.31818 MHz) divided by 12. In + * turn, the famous 4.77 MHz cpu clock frequency of the first IBM PC + * is this same NTSC frequency divided by 3. Why the NTSC frequency as + * a base "standard" ? Because the 14.31818 MHz quartz were cheap at + * that time, and because it allows to simply drive altogether the + * cpu, the "time of day" timer, and the video signal generators. + */ +sos_ret_t sos_i8254_set_frequency(unsigned int freq) +{ + unsigned int nb_tick; + + if (freq <= 0) + return -SOS_EINVAL; + + /* Compute counter value */ + nb_tick = I8254_MAX_FREQ / freq; + + /* Counter must be between 1 and 65536 */ + if (nb_tick > 65536) + return -SOS_EINVAL; + if (nb_tick <= 0) + return -SOS_EINVAL; + + /* The i8254 interprets 0 to mean counter == 65536, because 65536 + cannot be coded on 16bits */ + if (nb_tick == 65536) + nb_tick = 0; + + /* We want to configure timer0, we want to send both LSB+MSB to set + timer0 freq (-> 0x30), and we configure timer0 in mode 2, ie as a + rate generator (-> 0x4) ==> 0x34 */ + outb(0x34, I8254_CONTROL); + + /* Send LSB of counter first */ + outb((nb_tick & 0xFF), I8254_TIMER0); + + /* Send MSB of counter */ + outb((nb_tick >> 8) & 0xFF, I8254_TIMER0); + + return SOS_OK; +} diff --git a/sos-code-article4/hwcore/i8254.h b/sos-code-article4/hwcore/i8254.h new file mode 100644 index 0000000..4838ff4 --- /dev/null +++ b/sos-code-article4/hwcore/i8254.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_i8259_H_ +#define _SOS_i8259_H_ + +#include <sos/errno.h> + +/** + * @file i8254.h PC programmable timer + * + * Programmable timer routines. See the Intel 82C54 datasheet (on kos + * website). + * + * @see i82C54 datasheet on Kos website. + */ + +/** Change timer interrupt (IRQ 0) frequency */ +sos_ret_t sos_i8254_set_frequency(unsigned int freq); + +#endif /* _SOS_i8259_H_ */ diff --git a/sos-code-article4/hwcore/i8259.c b/sos-code-article4/hwcore/i8259.c new file mode 100644 index 0000000..8391c07 --- /dev/null +++ b/sos-code-article4/hwcore/i8259.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2004 The KOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "ioports.h" + +#include "i8259.h" + +#define PIC_MASTER 0x20 +#define PIC_SLAVE 0xa0 + +/** Setup the 8259 PIC */ +sos_ret_t sos_i8259_setup(void) +{ + /* Send ICW1: 8086 mode + NOT Single ctrl + call address + interval=8 */ + outb(0x11, PIC_MASTER); + outb(0x11, PIC_SLAVE); + + /* Send ICW2: ctrl base address */ + outb(0x20, PIC_MASTER+1); + outb(0x28, PIC_SLAVE+1); + + /* Send ICW3 master: mask where slaves are connected */ + outb(0x4, PIC_MASTER+1); + /* Send ICW3 slave: index where the slave is connected on master */ + outb(0x2, PIC_SLAVE+1); + + /* Send ICW4: 8086 mode, fully nested, not buffered, no implicit EOI */ + outb(0x1, PIC_MASTER+1); + outb(0x1, PIC_SLAVE+1); + + /* Send OCW1: + * Closing all IRQs : waiting for a correct handler The only IRQ + * enabled is the cascade (that's why we use 0xFB for the master) */ + outb(0xFB, PIC_MASTER+1); + outb(0xFF, PIC_SLAVE+1); + + return SOS_OK; +} + + +sos_ret_t sos_i8259_enable_irq_line(int numirq) +{ + if(numirq < 8) + /* irq on master PIC */ + outb((inb(PIC_MASTER+1) & ~(1 << numirq)), PIC_MASTER+1); + else + /* irq on slave PIC */ + outb((inb(PIC_SLAVE+1) & ~(1 << (numirq-8))), PIC_SLAVE+1); + + return SOS_OK; +} + + +sos_ret_t sos_i8259_disable_irq_line(int numirq) +{ + if(numirq < 8) + /* irq on master PIC */ + outb((inb(PIC_MASTER+1) | (1 << numirq)), PIC_MASTER+1); + else + /* irq on slave PIC */ + outb((inb(PIC_SLAVE+1) | (1 << (numirq-8))), PIC_SLAVE+1); + + return SOS_OK; +} diff --git a/sos-code-article4/hwcore/i8259.h b/sos-code-article4/hwcore/i8259.h new file mode 100644 index 0000000..c1771dd --- /dev/null +++ b/sos-code-article4/hwcore/i8259.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_i8259_H_ +#define _SOS_i8259_H_ + +#include <sos/errno.h> + +/** + * @file i8259.h PIC + * + * PIC Management routines. See the Intel 8259A datasheet (on kos + * website), page 9+. Should be not be used directly: only interrupt.c + * should use this. + * + * @see i8259A datasheet on Kos website. + */ + +/** Setup PIC and Disable all IRQ lines */ +sos_ret_t sos_i8259_setup(void); + +sos_ret_t sos_i8259_enable_irq_line(int numirq); + +sos_ret_t sos_i8259_disable_irq_line(int numirq); + +#endif /* _SOS_i8259_H_ */ diff --git a/sos-code-article4/hwcore/idt.c b/sos-code-article4/hwcore/idt.c new file mode 100644 index 0000000..51e3a9d --- /dev/null +++ b/sos-code-article4/hwcore/idt.c @@ -0,0 +1,160 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "segment.h" + +#include "idt.h" + +/** + * An entry in the IDT, or "IDTE" in the following, ie a reference to + * a interrupt/trap routine or a task gate to handle the sw/hw + * interrupts and exceptions. + * + * @see figure 5-2, intel x86 doc, vol 3 + */ +struct x86_idt_entry +{ + /* Low dword */ + sos_ui16_t offset_low; /* 15..0, offset of the routine in the segment */ + sos_ui16_t seg_sel; /* 31..16, the ID of the segment */ + + /* High dword */ + sos_ui8_t reserved:5; /* 4..0 */ + sos_ui8_t flags:3; /* 7..5 */ + sos_ui8_t type:3; /* 10..8 (interrupt gate, trap gate...) */ + sos_ui8_t op_size:1; /* 11 (0=16bits instructions, 1=32bits instr.) */ + sos_ui8_t zero:1; /* 12 */ + sos_ui8_t dpl:2; /* 14..13 */ + sos_ui8_t present:1; /* 15 */ + sos_ui16_t offset_high; /* 31..16 */ +} __attribute__((packed)); + + +/** + * The IDT register, which stores the address and size of the + * IDT. + * + * @see Intel x86 doc vol 3, section 2.4, figure 2-4 + */ +struct x86_idt_register +{ + /* The maximum GDT offset allowed to access an entry in the GDT */ + sos_ui16_t limit; + + /* This is not exactly a "virtual" address, ie an adddress such as + those of instructions and data; this is a "linear" address, ie an + address in the paged memory. However, in SOS we configure the + segmented memory as a "flat" space: the 0-4GB segment-based (ie + "virtual") addresses directly map to the 0-4GB paged memory (ie + "linear"), so that the "linear" addresses are numerically equal + to the "virtual" addresses: this base_addr will thus be the same + as the address of the gdt array */ + sos_ui32_t base_addr; +} __attribute__((packed, aligned (8))); + + +static struct x86_idt_entry idt[SOS_IDTE_NUM]; + +sos_ret_t sos_idt_setup() +{ + struct x86_idt_register idtr; + int i; + + for (i = 0 ; + i < SOS_IDTE_NUM ; + i++) + { + struct x86_idt_entry *idte = idt + i; + + /* Setup an empty IDTE interrupt gate, see figure 5-2 in Intel + x86 doc, vol 3 */ + idte->seg_sel = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE); + idte->reserved = 0; + idte->flags = 0; + idte->type = 0x6; /* Interrupt gate (110b) */ + idte->op_size = 1; /* 32bits instructions */ + idte->zero = 0; + + /* Disable this IDT entry for the moment */ + sos_idt_set_handler(i, (sos_vaddr_t)NULL, 0/* Don't care */); + } + + /* + * Setup the IDT register, see Intel x86 doc vol 3, section 5.8. + */ + + /* Address of the IDT */ + idtr.base_addr = (sos_ui32_t) idt; + + /* The limit is the maximum offset in bytes from the base address of + the IDT */ + idtr.limit = sizeof(idt) - 1; + + /* Commit the IDT into the CPU */ + asm volatile ("lidt %0\n"::"m"(idtr):"memory"); + + return SOS_OK; +} + + +sos_ret_t sos_idt_set_handler(int index, + sos_vaddr_t handler_address, + int lowest_priviledge /* 0..3 */) +{ + struct x86_idt_entry *idte; + + if ((index < 0) || (index >= SOS_IDTE_NUM)) + return -SOS_EINVAL; + if ((lowest_priviledge < 0) || (lowest_priviledge > 3)) + return -SOS_EINVAL; + + idte = idt + index; + if (handler_address != (sos_vaddr_t)NULL) + { + idte->offset_low = handler_address & 0xffff; + idte->offset_high = (handler_address >> 16) & 0xffff; + idte->dpl = lowest_priviledge; + idte->present = 1; /* Yes, there is a handler */ + } + else /* Disable this IDT entry */ + { + idte->offset_low = 0; + idte->offset_high = 0; + idte->dpl = 0; + idte->present = 0; /* No, there is no handler */ + } + + return SOS_OK; +} + + +sos_ret_t sos_idt_get_handler(int index, + sos_vaddr_t *handler_address, + int *lowest_priviledge) +{ + if ((index < 0) || (index >= SOS_IDTE_NUM)) + return -SOS_EINVAL; + + if (handler_address != NULL) + *handler_address = idt[index].offset_low + | (idt[index].offset_high << 16); + if (lowest_priviledge != NULL) + *lowest_priviledge = idt[index].dpl; + + return SOS_OK; +} diff --git a/sos-code-article4/hwcore/idt.h b/sos-code-article4/hwcore/idt.h new file mode 100644 index 0000000..7afe364 --- /dev/null +++ b/sos-code-article4/hwcore/idt.h @@ -0,0 +1,85 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_IDT_H_ +#define _SOS_IDT_H_ + +/** + * @file idt.h + * + * Manage the x86 Interrupt Descriptor Table, the table which maps the + * hardware interrupt lines, hardware exceptions, and software + * interrupts, to software routines. We only define "interrupt gate" + * IDT entries. Don't use it directly; refer instead to interrupt.c, + * exceptions.c and syscall.c. + * + * @see Intel x86 doc, Vol 3, chapter 5 + */ + +#include <sos/errno.h> +#include <sos/types.h> + +/* Mapping of the CPU exceptions in the IDT (imposed by Intel + standards) */ +#define SOS_EXCEPT_BASE 0 +#define SOS_EXCEPT_NUM 32 +#define SOS_EXCEPT_MAX (SOS_HWEXCEPT_BASE + SOS_HWEXCEPT_NUM - 1) + +/* Mapping of the IRQ lines in the IDT */ +#define SOS_IRQ_BASE 32 +#define SOS_IRQ_NUM 16 +#define SOS_IRQ_MAX (SOS_IRQ_BASE + SOS_IRQ_NUM - 1) + +/** + * Number of IDT entries. + * + * @note Must be large enough to map the hw interrupts, the exceptions + * (=> total is 48 entries), and the syscall(s). Since our syscall + * will be 0x42, it must be >= 0x43. Intel doc limits this to 256 + * entries, we use this limit. + */ +#define SOS_IDTE_NUM 256 /* 0x100 */ + +/** Initialization routine: all the IDT entries (or "IDTE") are marked + "not present". */ +sos_ret_t sos_idt_setup(void); + +/** + * Enable the IDT entry if handler_address != NULL, with the given + * lowest_priviledge.\ Disable the IDT entry when handler_address == + * NULL (the lowest_priviledge parameter is then ignored). Intel doc + * says that there must not be more than 256 entries. + * + * @note IRQ Unsafe + */ +sos_ret_t sos_idt_set_handler(int index, + sos_vaddr_t handler_address, + int lowest_priviledge /* 0..3 */); + + +/** + * @note IRQ Unsafe + * + * @return the handler address and DPL in the 2nd and 3rd + * parameters + */ +sos_ret_t sos_idt_get_handler(int index, + sos_vaddr_t *handler_address, + int *lowest_priviledge); + +#endif /* _SOS_IDT_H_ */ diff --git a/sos-code-article4/hwcore/ioports.h b/sos-code-article4/hwcore/ioports.h new file mode 100644 index 0000000..443acb7 --- /dev/null +++ b/sos-code-article4/hwcore/ioports.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2004 All GPL'ed OS + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_IOPORTS_H_ +#define _SOS_IOPORTS_H_ + +/** + * @ioports.h + * + * Intel-specific I/O space access routines. + */ + +/* This macro allows to write to an I/O port */ +#define outb(value, port) \ + __asm__ volatile ( \ + "outb %b0,%w1" \ + ::"a" (value),"Nd" (port) \ + ) \ + +// read one byte from port +#define inb(port) \ +({ \ + unsigned char _v; \ + __asm__ volatile ( \ + "inb %w1,%0" \ + :"=a" (_v) \ + :"Nd" (port) \ + ); \ + _v; \ +}) + +#endif /* _SOS_IOPORTS_H_ */ diff --git a/sos-code-article4/hwcore/irq.c b/sos-code-article4/hwcore/irq.c new file mode 100644 index 0000000..6ec3371 --- /dev/null +++ b/sos-code-article4/hwcore/irq.c @@ -0,0 +1,91 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "idt.h" +#include "i8259.h" + +#include "irq.h" + +/* array of IRQ wrappers, defined in irq_wrappers.S */ +extern sos_vaddr_t sos_irq_wrapper_array[SOS_IRQ_NUM]; + +/* arrays of IRQ handlers, shared with irq_wrappers.S */ +sos_irq_handler_t sos_irq_handler_array[SOS_IRQ_NUM] = { NULL, }; + + +sos_ret_t sos_irq_setup(void) +{ + return sos_i8259_setup(); +} + + +sos_ret_t sos_irq_set_routine(int irq_level, + sos_irq_handler_t routine) +{ + sos_ret_t retval; + sos_ui32_t flags; + + if ((irq_level < 0) || (irq_level >= SOS_IRQ_NUM)) + return -SOS_EINVAL; + + sos_disable_IRQs(flags); + + retval = SOS_OK; + + /* Set the irq routine to be called by the IRQ wrapper */ + sos_irq_handler_array[irq_level] = routine; + + /* If the irq is to be enabled, update the IDT with the IRQ + wrapper */ + if (routine != NULL) + { + retval + = sos_idt_set_handler(SOS_IRQ_BASE + irq_level, + (sos_vaddr_t) sos_irq_wrapper_array[irq_level], + 0 /* CPL0 routine */); + /* A problem occured */ + if (retval != SOS_OK) + sos_irq_handler_array[irq_level] = NULL; + } + else /* Disable this idt entry */ + { + retval + = sos_idt_set_handler(SOS_IRQ_BASE + irq_level, + (sos_vaddr_t)NULL /* Disable IDTE */, + 0 /* Don't care */); + } + + /* Update the PIC only if an IRQ handler has been set */ + if (sos_irq_handler_array[irq_level] != NULL) + sos_i8259_enable_irq_line(irq_level); + else + sos_i8259_disable_irq_line(irq_level); + + sos_restore_IRQs(flags); + return retval; +} + + +sos_irq_handler_t sos_irq_get_routine(int irq_level) +{ + if ((irq_level < 0) || (irq_level >= SOS_IRQ_NUM)) + return NULL; + + /* Expected to be atomic */ + return sos_irq_handler_array[irq_level]; +} diff --git a/sos-code-article4/hwcore/irq.h b/sos-code-article4/hwcore/irq.h new file mode 100644 index 0000000..5b39230 --- /dev/null +++ b/sos-code-article4/hwcore/irq.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2004 David Decotigny + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_HWINTR_H_ +#define _SOS_HWINTR_H_ + +/** + * @file irq.c + * + * Hardware interrupts routines management. + */ + +#include <sos/errno.h> + +#define sos_save_flags(flags) \ + asm volatile("pushfl ; popl %0":"=g"(flags)::"memory") +#define sos_restore_flags(flags) \ + asm volatile("push %0; popfl"::"g"(flags):"memory") + +#define sos_disable_IRQs(flags) \ + ({ sos_save_flags(flags); asm("cli\n"); }) +#define sos_restore_IRQs(flags) \ + sos_restore_flags(flags) + +/* Usual IRQ levels */ +#define SOS_IRQ_TIMER 0 +#define SOS_IRQ_KEYBOARD 1 +#define SOS_IRQ_SLAVE_PIC 2 +#define SOS_IRQ_COM2 3 +#define SOS_IRQ_COM1 4 +#define SOS_IRQ_LPT2 5 +#define SOS_IRQ_FLOPPY 6 +#define SOS_IRQ_LPT1 7 +#define SOS_IRQ_8_NOT_DEFINED 8 +#define SOS_IRQ_RESERVED_1 9 +#define SOS_IRQ_RESERVED_2 10 +#define SOS_IRQ_RESERVED_3 11 +#define SOS_IRQ_RESERVED_4 12 +#define SOS_IRQ_COPROCESSOR 13 +#define SOS_IRQ_HARDDISK 14 +#define SOS_IRQ_RESERVED_5 15 + +typedef void (*sos_irq_handler_t)(int irq_level); + +/** Setup the PIC */ +sos_ret_t sos_irq_setup(void); + +/** + * If the routine is not NULL, the IDT is setup to call an IRQ + * wrapper upon interrupt, which in turn will call the routine, and + * the PIC is programmed to raise an irq.\ If the routine is + * NULL, we disable the irq line. + */ +sos_ret_t sos_irq_set_routine(int irq_level, + sos_irq_handler_t routine); + +sos_irq_handler_t sos_irq_get_routine(int irq_level); + +#endif /* _SOS_HWINTR_H_ */ diff --git a/sos-code-article4/hwcore/irq_wrappers.S b/sos-code-article4/hwcore/irq_wrappers.S new file mode 100644 index 0000000..cf3355d --- /dev/null +++ b/sos-code-article4/hwcore/irq_wrappers.S @@ -0,0 +1,173 @@ +/* Copyright (C) 2004 The KOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#define ASM_SOURCE 1 + +.file "irq_wrappers.S" + +.text + +/* The address of the table of handlers (defined in irq.c) */ +.extern sos_irq_handler_array + +/* The address of the table of wrappers (defined below, and shared + with irq.c */ +.globl sos_irq_wrapper_array + + +/* These pre-handlers are for IRQ (Master PIC) */ +.irp id, 0,1,2,3,4,5,6,7 + + .p2align 2, 0x90 + + sos_irq_wrapper_\id: + .type sos_irq_wrapper_\id,@function + + /* + * Backup the CPU context + */ + + /* Fake error code */ + pushl $0 + + /* Backup the actual context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Send EOI to PIC. See Intel 8259 datasheet + available on Kos website */ + movb $0x20, %al + outb %al, $0x20 + + /* + * Call the handler with IRQ number as argument + */ + pushl $\id + leal sos_irq_handler_array,%edi + call *\id*4(%edi) + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + + /* Remove fake error code */ + addl $4, %esp + + iret + .endr + + +/* These pre-handlers are for IRQ (Slave PIC) */ +.irp id, 8,9,10,11,12,13,14,15 + + .p2align 2, 0x90 + + sos_irq_wrapper_\id: + .type sos_irq_wrapper_\id,@function + + /* + * Backup the CPU context + */ + + /* Fake error code */ + pushl $0 + + /* Backup the actual context */ + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Send EOI to PIC. See Intel 8259 datasheet + available on Kos website */ + movb $0x20, %al + outb %al, $0xa0 + outb %al, $0x20 + + /* + * Call the handler with IRQ number as argument + */ + pushl $\id + leal sos_irq_handler_array,%edi + call *\id*4(%edi) + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + + /* Remove fake error code */ + addl $4, %esp + + iret + .endr + +/* Build the sos_irq_wrapper_array, shared with irq.c */ +.section ".rodata" +.p2align 5, 0x0 +sos_irq_wrapper_array: + .irp id, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .long (sos_irq_wrapper_\id) + .endr diff --git a/sos-code-article4/hwcore/paging.c b/sos-code-article4/hwcore/paging.c new file mode 100644 index 0000000..5968adf --- /dev/null +++ b/sos-code-article4/hwcore/paging.c @@ -0,0 +1,455 @@ +/* Copyright (C) 2004 David Decotigny + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <sos/physmem.h> +#include <sos/klibc.h> +#include <sos/assert.h> + +#include "paging.h" + +/** The structure of a page directory entry. See Intel vol 3 section + 3.6.4 */ +struct x86_pde +{ + sos_ui32_t present :1; /* 1=PT mapped */ + sos_ui32_t write :1; /* 0=read-only, 1=read/write */ + sos_ui32_t user :1; /* 0=supervisor, 1=user */ + sos_ui32_t write_through :1; /* 0=write-back, 1=write-through */ + sos_ui32_t cache_disabled :1; /* 1=cache disabled */ + sos_ui32_t accessed :1; /* 1=read/write access since last clear */ + sos_ui32_t zero :1; /* Intel reserved */ + sos_ui32_t page_size :1; /* 0=4kB, 1=4MB or 2MB (depending on PAE) */ + sos_ui32_t global_page :1; /* Ignored (Intel reserved) */ + sos_ui32_t custom :3; /* Do what you want with them */ + sos_ui32_t pt_paddr :20; +} __attribute__ ((packed)); + + +/** The structure of a page table entry. See Intel vol 3 section + 3.6.4 */ +struct x86_pte +{ + sos_ui32_t present :1; /* 1=PT mapped */ + sos_ui32_t write :1; /* 0=read-only, 1=read/write */ + sos_ui32_t user :1; /* 0=supervisor, 1=user */ + sos_ui32_t write_through :1; /* 0=write-back, 1=write-through */ + sos_ui32_t cache_disabled :1; /* 1=cache disabled */ + sos_ui32_t accessed :1; /* 1=read/write access since last clear */ + sos_ui32_t dirty :1; /* 1=write access since last clear */ + sos_ui32_t zero :1; /* Intel reserved */ + sos_ui32_t global_page :1; /* 1=No TLB invalidation upon cr3 switch + (when PG set in cr4) */ + sos_ui32_t custom :3; /* Do what you want with them */ + sos_ui32_t paddr :20; +} __attribute__ ((packed)); + + +/** Structure of the x86 CR3 register: the Page Directory Base + Register. See Intel x86 doc Vol 3 section 2.5 */ +struct x86_pdbr +{ + sos_ui32_t zero1 :3; /* Intel reserved */ + sos_ui32_t write_through :1; /* 0=write-back, 1=write-through */ + sos_ui32_t cache_disabled :1; /* 1=cache disabled */ + sos_ui32_t zero2 :7; /* Intel reserved */ + sos_ui32_t pd_paddr :20; +} __attribute__ ((packed)); + + +/** + * Helper macro to control the MMU: invalidate the TLB entry for the + * page located at the given virtual address. See Intel x86 vol 3 + * section 3.7. + */ +#define invlpg(vaddr) \ + do { \ + __asm__ __volatile__("invlpg %0"::"m"(*((unsigned *)(vaddr)))); \ + } while(0) + + +/** + * Helper macro to control the MMU: invalidate the whole TLB. See + * Intel x86 vol 3 section 3.7. + */ +#define flush_tlb() \ + do { \ + unsigned long tmpreg; \ + asm volatile("movl %%cr3,%0\n\tmovl %0,%%cr3" :"=r" \ + (tmpreg) : :"memory"); \ + } while (0) + + +/** + * Helper macro to compute the index in the PD for the given virtual + * address + */ +#define virt_to_pd_index(vaddr) \ + (((unsigned)(vaddr)) >> 22) + + +/** + * Helper macro to compute the index in the PT for the given virtual + * address + */ +#define virt_to_pt_index(vaddr) \ + ( (((unsigned)(vaddr)) >> 12) & 0x3ff ) + + +/** + * Helper macro to compute the offset in the page for the given virtual + * address + */ +#define virt_to_page_offset(vaddr) \ + (((unsigned)(vaddr)) & SOS_PAGE_MASK) + + +/** + * Helper function to map a page in the pd.\ Suppose that the RAM + * is identity mapped to resolve PT actual (CPU) address from the PD + * entry + */ +static sos_ret_t paging_setup_map_helper(struct x86_pde * pd, + sos_paddr_t ppage, + sos_vaddr_t vaddr) +{ + /* Get the page directory entry and table entry index for this + address */ + unsigned index_in_pd = virt_to_pd_index(vaddr); + unsigned index_in_pt = virt_to_pt_index(vaddr); + + /* Make sure the page table was mapped */ + struct x86_pte * pt; + if (pd[index_in_pd].present) + { + pt = (struct x86_pte*) (pd[index_in_pd].pt_paddr << 12); + + /* If we allocate a new entry in the PT, increase its reference + count. This test will always be TRUE here, since the setup + routine scans the kernel pages in a strictly increasing + order: at each step, the map will result in the allocation of + a new PT entry. For the sake of clarity, we keep the test + here. */ + if (! pt[index_in_pt].present) + sos_physmem_ref_physpage_at((sos_paddr_t)pt); + + /* The previous test should always be TRUE */ + else + SOS_ASSERT_FATAL(FALSE); /* indicate a fatal error */ + } + else + { + /* No : allocate a new one */ + pt = (struct x86_pte*) sos_physmem_ref_physpage_new(FALSE); + if (! pt) + return -SOS_ENOMEM; + + memset((void*)pt, 0x0, SOS_PAGE_SIZE); + + pd[index_in_pd].present = TRUE; + pd[index_in_pd].write = 1; /* It would be too complicated to + determine whether it + corresponds to a real R/W area + of the kernel code/data or + read-only */ + pd[index_in_pd].pt_paddr = ((sos_paddr_t)pt) >> 12; + } + + + /* Map the page in the page table */ + pt[index_in_pt].present = 1; + pt[index_in_pt].write = 1; /* It would be too complicated to + determine whether it corresponds to + a real R/W area of the kernel + code/data or R/O only */ + pt[index_in_pt].user = 0; + pt[index_in_pt].paddr = ppage >> 12; + + return SOS_OK; +} + + +sos_ret_t sos_paging_setup(sos_paddr_t identity_mapping_base, + sos_paddr_t identity_mapping_top) +{ + /* The PDBR we will setup below */ + struct x86_pdbr cr3; + + /* Get the PD for the kernel */ + struct x86_pde * pd + = (struct x86_pde*) sos_physmem_ref_physpage_new(FALSE); + + /* The iterator for scanning the kernel area */ + sos_paddr_t paddr; + + /* Reset the PD. For the moment, there is still an IM for the whole + RAM, so that the paddr are also vaddr */ + memset((void*)pd, + 0x0, + SOS_PAGE_SIZE); + + /* Identity-map the identity_mapping_* area */ + for (paddr = identity_mapping_base ; + paddr < identity_mapping_top ; + paddr += SOS_PAGE_SIZE) + { + if (paging_setup_map_helper(pd, paddr, paddr)) + return -SOS_ENOMEM; + } + + /* Identity-map the PC-specific BIOS/Video area */ + for (paddr = BIOS_N_VIDEO_START ; + paddr < BIOS_N_VIDEO_END ; + paddr += SOS_PAGE_SIZE) + { + if (paging_setup_map_helper(pd, paddr, paddr)) + return -SOS_ENOMEM; + } + + /* Ok, kernel is now identity mapped in the PD. We still have to set + up the mirroring */ + pd[virt_to_pd_index(SOS_PAGING_MIRROR_VADDR)].present = TRUE; + pd[virt_to_pd_index(SOS_PAGING_MIRROR_VADDR)].write = 1; + pd[virt_to_pd_index(SOS_PAGING_MIRROR_VADDR)].user = 0; + pd[virt_to_pd_index(SOS_PAGING_MIRROR_VADDR)].pt_paddr + = ((sos_paddr_t)pd)>>12; + + /* We now just have to configure the MMU to use our PD. See Intel + x86 doc vol 3, section 3.6.3 */ + memset(& cr3, 0x0, sizeof(struct x86_pdbr)); /* Reset the PDBR */ + cr3.pd_paddr = ((sos_paddr_t)pd) >> 12; + + /* Actual loading of the PDBR in the MMU: setup cr3 + bits 31[Paging + Enabled] and 16[Write Protect] of cr0, see Intel x86 doc vol 3, + sections 2.5, 3.6.1 and 4.11.3 + note table 4-2 */ + asm volatile ("movl %0,%%cr3\n\t" + "movl %%cr0,%%eax\n\t" + "orl $0x80010000, %%eax\n\t" /* bit 31 | bit 16 */ + "movl %%eax,%%cr0\n\t" + "jmp 1f\n\t" + "1:\n\t" + "movl $2f, %%eax\n\t" + "jmp *%%eax\n\t" + "2:\n\t" ::"r"(cr3):"memory","eax"); + + /* + * Here, the only memory available is: + * - The BIOS+video area + * - the identity_mapping_base .. identity_mapping_top area + * - the PD mirroring area (4M) + * All accesses to other virtual addresses will generate a #PF + */ + + return SOS_OK; +} + + +/* Suppose that the current address is configured with the mirroring + * enabled to access the PD and PT. */ +sos_ret_t sos_paging_map(sos_paddr_t ppage_paddr, + sos_vaddr_t vpage_vaddr, + sos_bool_t is_user_page, + int flags) +{ + /* Get the page directory entry and table entry index for this + address */ + unsigned index_in_pd = virt_to_pd_index(vpage_vaddr); + unsigned index_in_pt = virt_to_pt_index(vpage_vaddr); + + /* Get the PD of the current context */ + struct x86_pde *pd = (struct x86_pde*) + (SOS_PAGING_MIRROR_VADDR + + SOS_PAGE_SIZE*virt_to_pd_index(SOS_PAGING_MIRROR_VADDR)); + + /* Address of the PT in the mirroring */ + struct x86_pte * pt = (struct x86_pte*) (SOS_PAGING_MIRROR_VADDR + + SOS_PAGE_SIZE*index_in_pd); + + /* The mapping of anywhere in the PD mirroring is FORBIDDEN ;) */ + if ((vpage_vaddr >= SOS_PAGING_MIRROR_VADDR) + && (vpage_vaddr < SOS_PAGING_MIRROR_VADDR + SOS_PAGING_MIRROR_SIZE)) + return -SOS_EINVAL; + + /* Map a page for the PT if necessary */ + if (! pd[index_in_pd].present) + { + /* No : allocate a new one */ + sos_paddr_t pt_ppage + = sos_physmem_ref_physpage_new(! (flags & SOS_VM_MAP_ATOMIC)); + if (! pt_ppage) + { + return -SOS_ENOMEM; + } + + pd[index_in_pd].present = TRUE; + pd[index_in_pd].write = 1; /* Ignored in supervisor mode, see + Intel vol 3 section 4.12 */ + pd[index_in_pd].user |= (is_user_page)?1:0; + pd[index_in_pd].pt_paddr = ((sos_paddr_t)pt_ppage) >> 12; + + /* + * The PT is now mapped in the PD mirroring + */ + + /* Invalidate TLB for the page we just added */ + invlpg(pt); + + /* Reset this new PT */ + memset((void*)pt, 0x0, SOS_PAGE_SIZE); + } + + /* If we allocate a new entry in the PT, increase its reference + count. */ + else if (! pt[index_in_pt].present) + sos_physmem_ref_physpage_at(pd[index_in_pd].pt_paddr << 12); + + /* Otherwise, that means that a physical page is implicitely + unmapped */ + else + sos_physmem_unref_physpage(pt[index_in_pt].paddr << 12); + + /* Map the page in the page table */ + pt[index_in_pt].present = TRUE; + pt[index_in_pt].write = (flags & SOS_VM_MAP_PROT_WRITE)?1:0; + pt[index_in_pt].user = (is_user_page)?1:0; + pt[index_in_pt].paddr = ppage_paddr >> 12; + sos_physmem_ref_physpage_at(ppage_paddr); + + /* + * The page is now mapped in the current address space + */ + + /* Invalidate TLB for the page we just added */ + invlpg(vpage_vaddr); + + return SOS_OK; +} + + +sos_ret_t sos_paging_unmap(sos_vaddr_t vpage_vaddr) +{ + sos_ret_t pt_unref_retval; + + /* Get the page directory entry and table entry index for this + address */ + unsigned index_in_pd = virt_to_pd_index(vpage_vaddr); + unsigned index_in_pt = virt_to_pt_index(vpage_vaddr); + + /* Get the PD of the current context */ + struct x86_pde *pd = (struct x86_pde*) + (SOS_PAGING_MIRROR_VADDR + + SOS_PAGE_SIZE*virt_to_pd_index(SOS_PAGING_MIRROR_VADDR)); + + /* Address of the PT in the mirroring */ + struct x86_pte * pt = (struct x86_pte*) (SOS_PAGING_MIRROR_VADDR + + SOS_PAGE_SIZE*index_in_pd); + + /* No page mapped at this address ? */ + if (! pd[index_in_pd].present) + return -SOS_EINVAL; + if (! pt[index_in_pt].present) + return -SOS_EINVAL; + + /* The unmapping of anywhere in the PD mirroring is FORBIDDEN ;) */ + if ((vpage_vaddr >= SOS_PAGING_MIRROR_VADDR) + && (vpage_vaddr < SOS_PAGING_MIRROR_VADDR + SOS_PAGING_MIRROR_SIZE)) + return -SOS_EINVAL; + + /* Reclaim the physical page */ + sos_physmem_unref_physpage(pt[index_in_pt].paddr << 12); + + /* Unmap the page in the page table */ + memset(pt + index_in_pt, 0x0, sizeof(struct x86_pte)); + + /* Invalidate TLB for the page we just unmapped */ + invlpg(vpage_vaddr); + + /* Reclaim this entry in the PT, which may free the PT */ + pt_unref_retval = sos_physmem_unref_physpage(pd[index_in_pd].pt_paddr << 12); + SOS_ASSERT_FATAL(pt_unref_retval >= 0); + if (pt_unref_retval > 0) + /* If the PT is now completely unused... */ + { + /* Release the PDE */ + memset(pd + index_in_pd, 0x0, sizeof(struct x86_pde)); + + /* Update the TLB */ + invlpg(pt); + } + + return SOS_OK; +} + + +int sos_paging_get_prot(sos_vaddr_t vaddr) +{ + int retval; + + /* Get the page directory entry and table entry index for this + address */ + unsigned index_in_pd = virt_to_pd_index(vaddr); + unsigned index_in_pt = virt_to_pt_index(vaddr); + + /* Get the PD of the current context */ + struct x86_pde *pd = (struct x86_pde*) + (SOS_PAGING_MIRROR_VADDR + + SOS_PAGE_SIZE*virt_to_pd_index(SOS_PAGING_MIRROR_VADDR)); + + /* Address of the PT in the mirroring */ + struct x86_pte * pt = (struct x86_pte*) (SOS_PAGING_MIRROR_VADDR + + SOS_PAGE_SIZE*index_in_pd); + + /* No page mapped at this address ? */ + if (! pd[index_in_pd].present) + return SOS_VM_MAP_PROT_NONE; + if (! pt[index_in_pt].present) + return SOS_VM_MAP_PROT_NONE; + + /* Default access right of an available page is "read" on x86 */ + retval = SOS_VM_MAP_PROT_READ; + if (pd[index_in_pd].write && pt[index_in_pt].write) + retval |= SOS_VM_MAP_PROT_WRITE; + + return retval; +} + + +sos_paddr_t sos_paging_get_paddr(sos_vaddr_t vaddr) +{ + /* Get the page directory entry and table entry index for this + address */ + unsigned index_in_pd = virt_to_pd_index(vaddr); + unsigned index_in_pt = virt_to_pt_index(vaddr); + unsigned offset_in_page = virt_to_page_offset(vaddr); + + /* Get the PD of the current context */ + struct x86_pde *pd = (struct x86_pde*) + (SOS_PAGING_MIRROR_VADDR + + SOS_PAGE_SIZE*virt_to_pd_index(SOS_PAGING_MIRROR_VADDR)); + + /* Address of the PT in the mirroring */ + struct x86_pte * pt = (struct x86_pte*) (SOS_PAGING_MIRROR_VADDR + + SOS_PAGE_SIZE*index_in_pd); + + /* No page mapped at this address ? */ + if (! pd[index_in_pd].present) + return (sos_paddr_t)NULL; + if (! pt[index_in_pt].present) + return (sos_paddr_t)NULL; + + return (pt[index_in_pt].paddr << 12) + offset_in_page; +} + diff --git a/sos-code-article4/hwcore/paging.h b/sos-code-article4/hwcore/paging.h new file mode 100644 index 0000000..38eb81a --- /dev/null +++ b/sos-code-article4/hwcore/paging.h @@ -0,0 +1,120 @@ +/* Copyright (C) 2004 David Decotigny + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_PAGING_H_ +#define _SOS_PAGING_H_ + +/** + * @file paging.h + * + * MMU management routines (arch-dependent). Setup the MMU without + * identity-mapping physical<->virtual addresses over the whole + * physical address space: a single, restricted and known, area is + * identity-mapped, the remaining kernel/user space is not. To access + * and manage the MMU translation tables (PD/PT on x86), we rely on a + * particular configuration, called "mirroring", where the top-level + * translation table (PD on x86) maps itself at a known and fixed (virtual) + * address. The only assumption for this to be possible is that the + * structure of the translation table entries are compatible at the + * different levels of vadddr->paddr translation process (PDE and PTE + * on x86 are Ok). Credits go to Christophe Avoinne for that. + */ + +#include <sos/types.h> +#include <sos/errno.h> + +/** + * sos_paging_map flags + */ +/** Usual virtual memory access rights */ +#define SOS_VM_MAP_PROT_NONE 0 +#define SOS_VM_MAP_PROT_READ (1<<0) +#define SOS_VM_MAP_PROT_WRITE (1<<1) +/* EXEC not supported */ +/** Mapping a page may involve an physical page allocation (for a new + PT), hence may potentially block */ +#define SOS_VM_MAP_ATOMIC (1<<31) + +/** Virtual address where the mirroring takes place */ +#define SOS_PAGING_MIRROR_VADDR 0x3fc00000 /* 1GB - 4MB */ +/** Length of the space reserved for the mirroring in the kernel + virtual space */ +#define SOS_PAGING_MIRROR_SIZE (1 << 22) /* 1 PD = 1024 Page Tables = 4MB */ + +/** + * Setup initial page directory structure where the kernel is + * identically-mapped, and the mirroring. This routine also + * identity-maps the BIOS and video areas, to allow some debugging + * text to be printed to the console. Finally, this routine installs + * the whole configuration into the MMU. + */ +sos_ret_t sos_paging_setup(sos_paddr_t identity_mapping_base, + sos_paddr_t identity_mapping_top); + +/** + * Map the given physical page at the given virtual address in the + * current address space. + * + * @note *IMPORTANT*: The physical page ppage_paddr *MUST* have been + * referenced by the caller through either a call to + * sos_physmem_ref_physpage_new() or sos_physmem_ref_physpage_at(). It + * would work if this were untrue, but this would be INCORRECT (it is + * expected that one is owning the page before mapping it, or + * otherwise the page could have been stolen by an interrupt or + * another thread). + * + * @param ppage_paddr The address of a physical page (page-aligned) + * @param vpage_vaddr The address of the virtual page (page-aligned) + * @param is_user_page TRUE when the page is available from user space + * @param flags A mask made of SOS_VM_* bits + * + * @note Unless the SOS_VM_MAP_ATOMIC bit is set in the flags, the + * function may potentially block, because a physical page may be + * allocated for a new PT. + */ +sos_ret_t sos_paging_map(sos_paddr_t ppage_paddr, + sos_vaddr_t vpage_vaddr, + sos_bool_t is_user_page, + int flags); + +/** + * Undo the mapping from vaddr to the underlying physical page (if any) + * @param vpage_vaddr The address of the virtual page (page-aligned) + */ +sos_ret_t sos_paging_unmap(sos_vaddr_t vpage_vaddr); + +/** + * Return the page protection flags (SOS_VM_MAP_PROT_*) associated + * with the address, or SOS_VM_MAP_PROT_NONE when page is not mapped + */ +int sos_paging_get_prot(sos_vaddr_t vaddr); + +/** + * Return the physical address of the given virtual address. Since page + * at physical addr 0 is not mapped, the NULL result means "page not + * mapped". + */ +sos_paddr_t sos_paging_get_paddr(sos_vaddr_t vaddr); + +/** + * Tell whether the address is physically mapped + */ +#define sos_paging_check_present(vaddr) \ + (sos_paging_get_paddr(vaddr) != NULL) + + +#endif /* _SOS_PAGING_H_ */ diff --git a/sos-code-article4/hwcore/segment.h b/sos-code-article4/hwcore/segment.h new file mode 100644 index 0000000..37bdf5e --- /dev/null +++ b/sos-code-article4/hwcore/segment.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_HWSEGS_H_ +#define _SOS_HWSEGS_H_ + +/** + * @file segments.h + * + * Global and local (GDT/LDT) segment descriptor definition and + * structure. These segments map virtual addresses (ie + * data/instruction addresses, relative to these segment descriptors) + * to linear addresses (ie addresses in the paged-memory space). + * + * @see Intel x86 doc, vol 3 chapter 3. + */ + +#include <sos/types.h> + +/* + * Global segment selectors (GDT) for SOS/x86. + * + * @see gdt.h + */ +#define SOS_SEG_NULL 0 /* NULL segment, unused by the procesor */ +#define SOS_SEG_KCODE 1 /* Kernel code segment */ +#define SOS_SEG_KDATA 2 /* Kernel data segment */ + + +/** + * Helper macro that builds a segment register's value + */ +#define SOS_BUILD_SEGMENT_REG_VALUE(desc_privilege,in_ldt,seg_index) \ + ( (((desc_privilege) & 0x3) << 0) \ + | (((in_ldt)?1:0) << 2) \ + | ((seg_index) << 3) ) + + +/* + * Local segment selectors (LDT) for SOS/x86 + */ +/* None */ + +#endif /* _SOS_HWSEGS_H_ */ diff --git a/sos-code-article4/sos/assert.h b/sos-code-article4/sos/assert.h new file mode 100644 index 0000000..a14ca0b --- /dev/null +++ b/sos-code-article4/sos/assert.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2004 The KOS Team + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_ASSERT_H_ +#define _SOS_ASSERT_H_ + +#include <drivers/bochs.h> +#include <drivers/x86_videomem.h> + +/** + * If the expr is FALSE, print a message and halt the machine + */ +#define SOS_ASSERT_FATAL(expr) \ + ({ \ + int __res=(int)(expr); \ + if (! __res) { \ + asm("cli\n"); /* disable interrupts -- x86 only */ \ + sos_bochs_printf("%s@%s:%d Assertion " # expr " failed\n", \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + sos_x86_videomem_printf(24, 0, 12, \ + "%s@%s:%d Assertion " # expr " failed", \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + for (;;) asm("hlt;") ; /* Infinite loop, ie simple system halt */ \ + } \ + }) + + +#endif /* _SOS_ASSERT_H_ */ diff --git a/sos-code-article4/sos/errno.h b/sos-code-article4/sos/errno.h new file mode 100644 index 0000000..2c7bada --- /dev/null +++ b/sos-code-article4/sos/errno.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_ERRNO_H_ +#define _SOS_ERRNO_H_ + +/** + * @file errno.h + * + * SOS return value codes and errors. + */ + +/* Positive values of the error codes */ +#define SOS_OK 0 /* No error */ +#define SOS_EINVAL 1 /* Invalid argument */ +#define SOS_ENOSUP 2 /* Operation not supported */ +#define SOS_ENOMEM 3 /* No available memory */ +#define SOS_EFATAL 255 /* Internal fatal error */ + +/* A negative value means that an error occured. For + * example -SOS_EINVAL means that the error was "invalid + * argument" */ +typedef int sos_ret_t; + +#endif /* _SOS_ERRNO_H_ */ diff --git a/sos-code-article4/sos/klibc.c b/sos-code-article4/sos/klibc.c new file mode 100644 index 0000000..277a15c --- /dev/null +++ b/sos-code-article4/sos/klibc.c @@ -0,0 +1,271 @@ +/* Copyright (C) 2004 David Decotigny (with INSA Rennes for vsnprintf) + Copyright (C) 2003 The KOS Team + Copyright (C) 1999 Free Software Foundation + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include "klibc.h" + +/* For an optimized version, see BSD sources ;) */ +void *memcpy(void *dst0, const void *src0, register unsigned int size) +{ + char *dst; + const char *src; + for (dst = (char*)dst0, src = (const char*)src0 ; + size > 0 ; + dst++, src++, size--) + *dst = *src; + return dst0; +} + +/* ditto */ +void *memset(void *dst0, register int c, register unsigned int length) +{ + char *dst; + for (dst = (char*) dst0 ; + length > 0 ; + dst++, length --) + *dst = (char)c; + return dst0; +} + +int memcmp(const void *s1, const void *s2, sos_size_t len) +{ + const unsigned char *c1, *c2; + unsigned int i; + + for (i = 0, c1 = s1, c2 = s2; i < len; i++, c1++, c2++) + { + if(*c1 != *c2) + return *c1 - *c2; + } + + return 0; +} + + +unsigned int strlen(register const char *str) +{ + unsigned int retval = 0; + + while (*str++) + retval++; + + return retval; +} + + +unsigned int strnlen(const char * s, sos_size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */continue; + + return sc - s; +} + + +char *strzcpy(register char *dst, register const char *src, register int len) +{ + int i; + + if (len <= 0) + return dst; + + for (i = 0; i < len; i++) + { + dst[i] = src[i]; + if(src[i] == '\0') + return dst; + } + + dst[len-1] = '\0'; + return dst; +} + + +char *strzcat (char *dest, const char *src, sos_size_t n) +{ + char *res = dest; + + for ( ; *dest ; dest++); + + for ( ; *src ; src++, dest++) { + *dest = *src; + n--; + if (n <= 0) + break; + } + + *dest = '\0'; + return res; +} + +int strcmp(register const char *s1, register const char *s2) +{ + while (*s1 == *s2++) + if (*s1++ == 0) + return (0); + + return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); +} + + +int strncmp(register const char *s1, register const char *s2, register int len) +{ + char c1 = '\0', c2 = '\0'; + + while (len > 0) + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + len--; + } + + return c1 - c2; +} + + +/* I (d2) borrowed and rewrote this for Nachos/INSA Rennes. Thanks to + them for having kindly allowed me to do so. */ +int vsnprintf(char *buff, sos_size_t len, const char * format, va_list ap) +{ + sos_size_t i, result; + + if (!buff || !format || (len < 0)) + return -1; + +#define PUTCHAR(thechar) \ + do { \ + if (result < len-1) \ + *buff++ = (thechar); \ + result++; \ + } while (0) + + result = 0; + for(i=0 ; format[i] != '\0' ; i++){ + switch (format[i]) + { + case '%': + i++; + switch(format[i]) + { + case '%': + { + PUTCHAR('%'); + break; + } + case 'i':; + case 'd': + { + int integer = va_arg(ap,int); + int cpt2 = 0; + char buff_int[16]; + + if (integer<0) + PUTCHAR('-'); + /* Ne fait pas integer = -integer ici parce que INT_MIN + n'a pas d'equivalent positif (int = [-2^31, 2^31-1]) */ + + do { + int m10 = integer%10; + m10 = (m10 < 0)? -m10:m10; + buff_int[cpt2++]=(char)('0'+ m10); + integer=integer/10; + } while(integer!=0); + + for(cpt2 = cpt2 - 1 ; cpt2 >= 0 ; cpt2--) + PUTCHAR(buff_int[cpt2]); + + break; + } + + case 'c': + { + int value = va_arg(ap,int); + PUTCHAR((char)value); + break; + } + + case 's': + { + char *string = va_arg(ap,char *); + if (! string) + string = "(null)"; + for( ; *string != '\0' ; string++) + PUTCHAR(*string); + break; + } + + case 'x': + { + unsigned int hexa = va_arg(ap,int); + unsigned int nb; + int i, had_nonzero = 0; + for(i=0 ; i < 8 ; i++) + { + nb = (unsigned int)(hexa << (i*4)); + nb = (nb >> 28) & 0xf; + // Skip the leading zeros + if (nb == 0) + { + if (had_nonzero) + PUTCHAR('0'); + } + else + { + had_nonzero = 1; + if (nb < 10) + PUTCHAR('0'+nb); + else + PUTCHAR('a'+(nb-10)); + } + } + if (! had_nonzero) + PUTCHAR('0'); + break; + } + break; + + default: + PUTCHAR('%'); + PUTCHAR(format[i]); + } + break; + + default: + PUTCHAR(format[i]); + } + } + + *buff = '\0'; + return result; +} + + +int snprintf(char * buff, sos_size_t len, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + len = vsnprintf(buff, len, format, ap); + va_end(ap); + + return len; +} diff --git a/sos-code-article4/sos/klibc.h b/sos-code-article4/sos/klibc.h new file mode 100644 index 0000000..a8b9d49 --- /dev/null +++ b/sos-code-article4/sos/klibc.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2003 The KOS Team + Copyright (C) 1999 Free Software Foundation + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_KLIBC_H_ +#define _SOS_KLIBC_H_ + +/** + * @file klibc.h + * + * Basic libc-style support for common useful functions (string.h, + * stdarg.h), some with slight non-standard behavior (see comments). + */ + +#include <sos/types.h> + +/* string.h functions */ + +void *memcpy(void *dst, const void *src, register unsigned int size ) ; +void *memset(void *dst, register int c, register unsigned int length ) ; +int memcmp(const void *s1, const void *s2, sos_size_t n); + +unsigned int strlen( register const char *str) ; +unsigned int strnlen(const char * s, sos_size_t maxlen); + +/** + * @note Same as strncpy(), with a slightly different semantic. + * Actually, strncpy(3C) says " The result will not be null-terminated + * if the length of 'from' is n or more.". Here, 'dst' is ALWAYS + * null-terminated. And its total len will ALWAYS be <= len, with + * null-terminating-char included. + */ +char *strzcpy( register char *dst, register const char *src, + register int len ) ; + +/** + * @note Same as strncat(), with the same semantic : 'dst' is ALWAYS + * null-terminated. And its total len will ALWAYS be <= len, with + * null-terminating-char included. + */ +char *strzcat (char *dest, const char *src, + const sos_size_t len); + +int strcmp(register const char *s1, register const char *s2 ); +int strncmp(register const char *s1, register const char *s2, + register int len ); + +/* Basic stdarg.h macros. Taken from gcc support files */ +#define __GNUC_VA_LIST +typedef void *__gnuc_va_list; +typedef __gnuc_va_list va_list; +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) +#define va_start(AP, LASTARG) \ + (AP = ((__gnuc_va_list) __builtin_next_arg (LASTARG))) +#define va_end(AP) \ + ((void)0) +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE)))) +#define __va_copy(dest, src) \ + (dest) = (src) + +/* stdarg.h functions. There might be a non-standard behavior: there + will always be a trailing '\0' in the resulting string */ +int vsnprintf(char *, sos_size_t, const char *, va_list); +int snprintf(char *, sos_size_t, const char *, /*args*/ ...) + __attribute__ ((format (printf, 3, 4))); + +#endif /* _SOS_KLIBC_H_ */ diff --git a/sos-code-article4/sos/list.h b/sos-code-article4/sos/list.h new file mode 100644 index 0000000..67e72f3 --- /dev/null +++ b/sos-code-article4/sos/list.h @@ -0,0 +1,186 @@ +/* Copyright (C) 2001 David Decotigny + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_LIST_H_ +#define _SOS_LIST_H_ + +/** + * @file list.h + * + * Circular doubly-linked lists implementation entirely based on C + * macros + */ + + +/* *_named are used when next and prev links are not exactly next + and prev. For instance when we have next_in_team, prev_in_team, + prev_global and next_global */ + +#define list_init_named(list,prev,next) \ + ((list) = NULL) + +#define list_singleton_named(list,item,prev,next) ({ \ + (item)->next = (item)->prev = (item); \ + (list) = (item); \ +}) + +#define list_is_empty_named(list,prev,next) \ + ((list) == NULL) + +#define list_get_head_named(list,prev,next) \ + (list) + +#define list_get_tail_named(list,prev,next) \ + ((list)?((list)->prev):NULL) + +/* Internal macro : insert before the head == insert at tail */ +#define __list_insert_atleft_named(before_this,item,prev,next) ({ \ + (before_this)->prev->next = (item); \ + (item)->prev = (before_this)->prev; \ + (before_this)->prev = (item); \ + (item)->next = (before_this); \ +}) + +/* @note Before_this and item are expected to be valid ! */ +#define list_insert_before_named(list,before_this,item,prev,next) ({ \ + __list_insert_atleft_named(before_this,item,prev,next); \ + if ((list) == (before_this)) (list) = (item); \ +}) + +/** @note After_this and item are expected to be valid ! */ +#define list_insert_after_named(list,after_this,item,prev,next) ({ \ + (after_this)->next->prev = (item); \ + (item)->next = (after_this)->next; \ + (after_this)->next = (item); \ + (item)->prev = (after_this); \ +}) + +#define list_add_head_named(list,item,prev,next) ({ \ + if (list) \ + list_insert_before_named(list,list,item,prev,next); \ + else \ + list_singleton_named(list,item,prev,next); \ + (list) = (item); \ +}) + +#define list_add_tail_named(list,item,prev,next) ({ \ + if (list) \ + __list_insert_atleft_named(list,item,prev,next); \ + else \ + list_singleton_named(list,item,prev,next); \ +}) + +/** @note NO check whether item really is in list ! */ +#define list_delete_named(list,item,prev,next) ({ \ + if ( ((item)->next == (item)) && ((item)->prev == (item)) ) \ + (item)->next = (item)->prev = (list) = NULL; \ + else { \ + (item)->prev->next = (item)->next; \ + (item)->next->prev = (item)->prev; \ + if ((item) == (list)) (list) = (item)->next; \ + (item)->prev = (item)->next = NULL; \ + } \ +}) + +#define list_pop_head_named(list,prev,next) ({ \ + typeof(list) __ret_elt = (list); \ + list_delete_named(list,__ret_elt,prev,next); \ + __ret_elt; }) + +/** Loop statement that iterates through all of its elements, from + head to tail */ +#define list_foreach_forward_named(list,iterator,nb_elements,prev,next) \ + for (nb_elements=0, (iterator) = (list) ; \ + (iterator) && (!nb_elements || ((iterator) != (list))) ; \ + nb_elements++, (iterator) = (iterator)->next ) + +/** Loop statement that iterates through all of its elements, from + tail back to head */ +#define list_foreach_backward_named(list,iterator,nb_elements,prev,next) \ + for (nb_elements=0, (iterator) = list_get_tail_named(list,prev,next) ; \ + (iterator) && (!nb_elements || \ + ((iterator) != list_get_tail_named(list,prev,next))) ; \ + nb_elements++, (iterator) = (iterator)->prev ) + +#define list_foreach_named list_foreach_forward_named + +/** True when we exitted early from the foreach loop (ie break) */ +#define list_foreach_early_break(list,iterator,nb_elements) \ + ((list) && ( \ + ((list) != (iterator)) || \ + ( ((list) == (iterator)) && (nb_elements == 0)) )) + +/** Loop statement that also removes the item at each iteration */ +#define list_collapse_named(list,iterator,prev,next) \ + for ( ; ({ ((iterator) = (list)) ; \ + if (list) list_delete_named(list,iterator,prev,next) ; \ + (iterator); }) ; ) + + +/* + * the same macros : assume that the prev and next fields are really + * named "prev" and "next" + */ + +#define list_init(list) \ + list_init_named(list,prev,next) + +#define list_singleton(list,item) \ + list_singleton_named(list,item,prev,next) + +#define list_is_empty(list) \ + list_is_empty_named(list,prev,next) + +#define list_get_head(list) \ + list_get_head_named(list,prev,next) \ + +#define list_get_tail(list) \ + list_get_tail_named(list,prev,next) \ + +/* @note Before_this and item are expected to be valid ! */ +#define list_insert_after(list,after_this,item) \ + list_insert_after_named(list,after_this,item,prev,next) + +/* @note After_this and item are expected to be valid ! */ +#define list_insert_before(list,before_this,item) \ + list_insert_before_named(list,before_this,item,prev,next) + +#define list_add_head(list,item) \ + list_add_head_named(list,item,prev,next) + +#define list_add_tail(list,item) \ + list_add_tail_named(list,item,prev,next) + +/* @note NO check whether item really is in list ! */ +#define list_delete(list,item) \ + list_delete_named(list,item,prev,next) + +#define list_pop_head(list) \ + list_pop_head_named(list,prev,next) + +#define list_foreach_forward(list,iterator,nb_elements) \ + list_foreach_forward_named(list,iterator,nb_elements,prev,next) + +#define list_foreach_backward(list,iterator,nb_elements) \ + list_foreach_backward_named(list,iterator,nb_elements,prev,next) + +#define list_foreach list_foreach_forward + +#define list_collapse(list,iterator) \ + list_collapse_named(list,iterator,prev,next) + +#endif /* _SOS_LIST_H_ */ diff --git a/sos-code-article4/sos/macros.h b/sos-code-article4/sos/macros.h new file mode 100644 index 0000000..b08f081 --- /dev/null +++ b/sos-code-article4/sos/macros.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2004 The KOS Team + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_MACROS_H_ +#define _SOS_MACROS_H_ + +/** Align on a boundary (MUST be a power of 2), so that return value <= val */ +#define SOS_ALIGN_INF(val,boundary) \ + (((unsigned)(val)) & (~((boundary)-1))) + +/** Align on a boundary (MUST be a power of 2), so that return value >= val */ +#define SOS_ALIGN_SUP(val,boundary) \ + ({ unsigned int __bnd=(boundary); \ + (((((unsigned)(val))-1) & (~(__bnd - 1))) + __bnd); }) + +/** + * @return TRUE if val is a power of 2. + * @note val is evaluated multiple times + */ +#define SOS_IS_POWER_OF_2(val) \ + ((((val) - 1) & (val)) == 0) + +#endif /* _SOS_MACROS_H_ */ diff --git a/sos-code-article4/sos/main.c b/sos-code-article4/sos/main.c new file mode 100644 index 0000000..7f54f70 --- /dev/null +++ b/sos-code-article4/sos/main.c @@ -0,0 +1,298 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +/* Include definitions of the multiboot standard */ +#include <bootstrap/multiboot.h> +#include <hwcore/idt.h> +#include <hwcore/gdt.h> +#include <hwcore/irq.h> +#include <hwcore/exception.h> +#include <hwcore/i8254.h> +#include <sos/list.h> +#include <sos/physmem.h> +#include <hwcore/paging.h> +#include <sos/list.h> +#include <sos/klibc.h> +#include <sos/assert.h> +#include <drivers/x86_videomem.h> +#include <drivers/bochs.h> + + +/* Helper function to display each bits of a 32bits integer on the + screen as dark or light carrets */ +static void display_bits(unsigned char row, unsigned char col, + unsigned char attribute, + sos_ui32_t integer) +{ + int i; + /* Scan each bit of the integer, MSb first */ + for (i = 31 ; i >= 0 ; i--) + { + /* Test if bit i of 'integer' is set */ + int bit_i = (integer & (1 << i)); + /* Ascii 219 => dark carret, Ascii 177 => light carret */ + unsigned char ascii_code = bit_i?219:177; + sos_x86_videomem_putchar(row, col++, + attribute, + ascii_code); + } +} + + +/* Clock IRQ handler */ +static void clk_it(int intid) +{ + static sos_ui32_t clock_count = 0; + + display_bits(0, 48, + SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE, + clock_count); + clock_count++; + +} + +/* Page fault exception handler */ +static void pgflt_ex(int exid) +{ + sos_bochs_printf("Got page fault\n"); + sos_x86_videomem_printf(10, 30, + SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE, + "Got EXPECTED (?) Page fault ! But where ???"); + for (;;) ; +} + +static void test_paging(sos_vaddr_t sos_kernel_core_top_vaddr) +{ + /* The (linear) address of the page holding the code we are + currently executing */ + sos_vaddr_t vpage_code = SOS_PAGE_ALIGN_INF(test_paging); + + /* The new physical page that will hold the code */ + sos_paddr_t ppage_new; + + /* Where this page will be mapped temporarily in order to copy the + code into it: right after the kernel code/data */ + sos_vaddr_t vpage_tmp = sos_kernel_core_top_vaddr; + + unsigned i; + + /* Bind the page fault exception to one of our routines */ + sos_exception_set_routine(SOS_EXCEPT_PAGE_FAULT, + pgflt_ex); + + /* + * Test 1: move the page where we execute the code elsewhere in + * physical memory + */ + sos_x86_videomem_printf(4, 0, + SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE, + "Moving current code elsewhere in physical memory:"); + + + /* Allocate a new physical page */ + ppage_new = sos_physmem_ref_physpage_new(FALSE); + if (! ppage_new) + { + /* STOP ! No memory left */ + sos_x86_videomem_putstring(20, 0, + SOS_X86_VIDEO_FG_LTRED + | SOS_X86_VIDEO_BG_BLUE, + "test_paging : Cannot allocate page"); + return; + } + + sos_x86_videomem_printf(5, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Hello from the address 0x%x in physical memory", + sos_paging_get_paddr(vpage_code)); + + sos_x86_videomem_printf(6, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Transfer vpage 0x%x: ppage 0x%x -> 0x%x (tmp vpage 0x%x)", + vpage_code, + sos_paging_get_paddr(vpage_code), + ppage_new, + (unsigned)vpage_tmp); + + /* Map the page somewhere (right after the kernel mapping) in order + to copy the code we are currently executing */ + sos_paging_map(ppage_new, vpage_tmp, + FALSE, + SOS_VM_MAP_ATOMIC + | SOS_VM_MAP_PROT_READ + | SOS_VM_MAP_PROT_WRITE); + + /* Ok, the new page is referenced by the mapping, we can release our + reference to it */ + sos_physmem_unref_physpage(ppage_new); + + /* Copy the contents of the current page of code to this new page + mapping */ + memcpy((void*)vpage_tmp, + (void*)vpage_code, + SOS_PAGE_SIZE); + + /* Transfer the mapping of the current page of code to this new page */ + sos_paging_map(ppage_new, vpage_code, + FALSE, + SOS_VM_MAP_ATOMIC + | SOS_VM_MAP_PROT_READ + | SOS_VM_MAP_PROT_WRITE); + + /* Ok, here we are: we have changed the physcal page that holds the + code we are executing ;). However, this new page is mapped at 2 + virtual addresses: + - vpage_tmp + - vpage_code + We can safely unmap it from sos_kernel_core_top_vaddr, while + still keeping the vpage_code mapping */ + sos_paging_unmap(vpage_tmp); + + sos_x86_videomem_printf(7, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Hello from the address 0x%x in physical memory", + sos_paging_get_paddr(vpage_code)); + + sos_x86_videomem_printf(9, 0, + SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE, + "Provoking a page fault:"); + + /* + * Test 2: make sure the #PF handler works + */ + + /* Scan part of the kernel up to a page fault. This page fault + should occur on the first page unmapped after the kernel area, + which is exactly the page we temporarily mapped/unmapped + (vpage_tmp) above to move the kernel code we are executing */ + for (i = vpage_code ; /* none */ ; i += SOS_PAGE_SIZE) + { + unsigned *pint = (unsigned *)SOS_PAGE_ALIGN_INF(i); + sos_bochs_printf("Test vaddr 0x%x : val=", (unsigned)pint); + sos_x86_videomem_printf(10, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Test vaddr 0x%x : val= ", + (unsigned)pint); + sos_bochs_printf("0x%x\n", *pint); + sos_x86_videomem_printf(10, 30, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "0x%x ", *pint); + } + + /* BAD ! Did not get the page fault... */ + sos_x86_videomem_printf(20, 0, + SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE, + "We should have had a #PF at vaddr 0x%x !", + vpage_tmp); +} + +/* The C entry point of our operating system */ +void sos_main(unsigned long magic, unsigned long addr) +{ + unsigned i; + sos_paddr_t sos_kernel_core_base_paddr, sos_kernel_core_top_paddr; + + /* Grub sends us a structure, called multiboot_info_t with a lot of + precious informations about the system, see the multiboot + documentation for more information. */ + multiboot_info_t *mbi; + mbi = (multiboot_info_t *) addr; + + /* Setup bochs and console, and clear the console */ + sos_bochs_setup(); + + sos_x86_videomem_setup(); + sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE); + + /* Greetings from SOS */ + if (magic == MULTIBOOT_BOOTLOADER_MAGIC) + /* Loaded with Grub */ + sos_x86_videomem_printf(1, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)", + "SOS", ',', + (unsigned)(mbi->mem_upper >> 10) + 1, + (unsigned)mbi->mem_upper); + else + /* Not loaded with grub */ + sos_x86_videomem_printf(1, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Welcome to SOS"); + + sos_bochs_putstring("Message in a bochs\n"); + + /* Setup CPU segmentation and IRQ subsystem */ + sos_gdt_setup(); + sos_idt_setup(); + + /* Setup SOS IRQs and exceptions subsystem */ + sos_exceptions_setup(); + sos_irq_setup(); + + /* Configure the timer so as to raise the IRQ0 at a 100Hz rate */ + sos_i8254_set_frequency(100); + + + /* We need a multiboot-compliant boot loader to get the size of the RAM */ + if (magic != MULTIBOOT_BOOTLOADER_MAGIC) + { + sos_x86_videomem_putstring(20, 0, + SOS_X86_VIDEO_FG_LTRED + | SOS_X86_VIDEO_BG_BLUE + | SOS_X86_VIDEO_FG_BLINKING, + "I'm not loaded with Grub !"); + /* STOP ! */ + for (;;) + continue; + } + + /* Binding some HW interrupts and exceptions to software routines */ + sos_irq_set_routine(SOS_IRQ_TIMER, + clk_it); + /* Enabling the HW interrupts here, this will make the timer HW + interrupt call our clk_it handler */ + asm volatile ("sti\n"); + /* Multiboot says: "The value returned for upper memory is maximally + the address of the first upper memory hole minus 1 megabyte.". It + also adds: "It is not guaranteed to be this value." aka "YMMV" ;) */ + sos_physmem_setup((mbi->mem_upper<<10) + (1<<20), + & sos_kernel_core_base_paddr, + & sos_kernel_core_top_paddr); + + /* + * Switch to paged-memory mode + */ + + /* Disabling interrupts should seem more correct, but it's not really + necessary at this stage */ + if (sos_paging_setup(sos_kernel_core_base_paddr, + sos_kernel_core_top_paddr)) + sos_bochs_printf("Could not setup paged memory mode\n"); + sos_x86_videomem_printf(2, 0, + SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, + "Paged-memory mode is activated"); + + test_paging(sos_kernel_core_top_paddr); + + /* An operatig system never ends */ + for (;;) + continue; + + return; +} diff --git a/sos-code-article4/sos/physmem.c b/sos-code-article4/sos/physmem.c new file mode 100644 index 0000000..99cffb7 --- /dev/null +++ b/sos-code-article4/sos/physmem.c @@ -0,0 +1,269 @@ +/* Copyright (C) 2004 David Decotigny + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#include <sos/list.h> +#include <sos/macros.h> +#include <sos/assert.h> +#include <sos/klibc.h> + +#include "physmem.h" + +/** A descriptor for a physical page in SOS */ +struct physical_page_descr +{ + /** The physical base address for the page */ + sos_paddr_t paddr; + + /** The reference count for this physical page. > 0 means that the + page is in the used list. */ + sos_count_t ref_cnt; + + /** The other pages on the list (used, free) */ + struct physical_page_descr *prev, *next; +}; + +/** These are some markers present in the executable file (see sos.lds) */ +extern char __b_kernel, __e_kernel; + +/** The array of ppage descriptors will be located at this address */ +#define PAGE_DESCR_ARRAY_ADDR \ + SOS_PAGE_ALIGN_SUP((sos_paddr_t) (& __e_kernel)) +static struct physical_page_descr * physical_page_descr_array; + +/** The list of physical pages currently available */ +static struct physical_page_descr *free_ppage; + +/** The list of physical pages currently in use */ +static struct physical_page_descr *used_ppage; + +/** We will store here the interval of valid physical addresses */ +static sos_paddr_t physmem_base, physmem_top; + +/** We store the number of pages used/free */ +static sos_count_t physmem_total_pages, physmem_used_pages; + +sos_ret_t sos_physmem_setup(sos_size_t ram_size, + /* out */sos_paddr_t *kernel_core_base, + /* out */sos_paddr_t *kernel_core_top) +{ + /* The iterator over the page descriptors */ + struct physical_page_descr *ppage_descr; + + /* The iterator over the physical addresses */ + sos_paddr_t ppage_addr; + + /* Make sure ram size is aligned on a page boundary */ + ram_size = SOS_PAGE_ALIGN_INF(ram_size);/* Yes, we may lose at most a page */ + + /* Reset the used/free page lists before building them */ + free_ppage = used_ppage = NULL; + physmem_total_pages = physmem_used_pages = 0; + + /* Make sure that there is enough memory to store the array of page + descriptors */ + *kernel_core_base = SOS_PAGE_ALIGN_INF((sos_paddr_t)(& __b_kernel)); + *kernel_core_top + = PAGE_DESCR_ARRAY_ADDR + + SOS_PAGE_ALIGN_SUP( (ram_size >> SOS_PAGE_SHIFT) + * sizeof(struct physical_page_descr)); + if (*kernel_core_top > ram_size) + return -SOS_ENOMEM; + + /* Page 0-4kB is not available in order to return address 0 as a + means to signal "no page available" */ + physmem_base = SOS_PAGE_SIZE; + physmem_top = ram_size; + + /* Setup the page descriptor arrray */ + physical_page_descr_array + = (struct physical_page_descr*)PAGE_DESCR_ARRAY_ADDR; + + /* Scan the list of physical pages */ + for (ppage_addr = 0, + ppage_descr = physical_page_descr_array ; + ppage_addr < physmem_top ; + ppage_addr += SOS_PAGE_SIZE, + ppage_descr ++) + { + enum { PPAGE_MARK_RESERVED, PPAGE_MARK_FREE, + PPAGE_MARK_KERNEL, PPAGE_MARK_HWMAP } todo; + + memset(ppage_descr, 0x0, sizeof(struct physical_page_descr)); + + /* Init the page descriptor for this page */ + ppage_descr->paddr = ppage_addr; + + /* Reserved : 0 ... base */ + if (ppage_addr < physmem_base) + todo = PPAGE_MARK_RESERVED; + + /* Free : base ... BIOS */ + else if ((ppage_addr >= physmem_base) + && (ppage_addr < BIOS_N_VIDEO_START)) + todo = PPAGE_MARK_FREE; + + /* Used : BIOS */ + else if ((ppage_addr >= BIOS_N_VIDEO_START) + && (ppage_addr < BIOS_N_VIDEO_END)) + todo = PPAGE_MARK_HWMAP; + + /* Free : BIOS ... kernel */ + else if ((ppage_addr >= BIOS_N_VIDEO_END) + && (ppage_addr < (sos_paddr_t) (& __b_kernel))) + todo = PPAGE_MARK_FREE; + + /* Used : Kernel code/data/bss + physcal page descr array */ + else if ((ppage_addr >= *kernel_core_base) + && (ppage_addr < *kernel_core_top)) + todo = PPAGE_MARK_KERNEL; + + /* Free : first page of descr ... end of RAM */ + else + todo = PPAGE_MARK_FREE; + + /* Actually does the insertion in the used/free page lists */ + physmem_total_pages ++; + switch (todo) + { + case PPAGE_MARK_FREE: + ppage_descr->ref_cnt = 0; + list_add_head(free_ppage, ppage_descr); + break; + + case PPAGE_MARK_KERNEL: + case PPAGE_MARK_HWMAP: + ppage_descr->ref_cnt = 1; + list_add_head(used_ppage, ppage_descr); + physmem_used_pages ++; + break; + + default: + /* Reserved page: nop */ + break; + } + } + + return SOS_OK; +} + + +sos_paddr_t sos_physmem_ref_physpage_new(sos_bool_t can_block) +{ + struct physical_page_descr *ppage_descr; + + if (! free_ppage) + return (sos_paddr_t)NULL; + + /* Retrieve a page in the free list */ + ppage_descr = list_pop_head(free_ppage); + + /* The page is assumed not to be already used */ + SOS_ASSERT_FATAL(ppage_descr->ref_cnt == 0); + + /* Mark the page as used (this of course sets the ref count to 1) */ + ppage_descr->ref_cnt ++; + + /* Put the page in the used list */ + list_add_tail(used_ppage, ppage_descr); + physmem_used_pages ++; + + return ppage_descr->paddr; +} + + +/** + * Helper function to get the physical page descriptor for the given + * physical page address. + * + * @return NULL when out-of-bounds or non-page-aligned + */ +inline static struct physical_page_descr * +get_page_descr_at_paddr(sos_paddr_t ppage_paddr) +{ + /* Don't handle non-page-aligned addresses */ + if (ppage_paddr & SOS_PAGE_MASK) + return NULL; + + /* Don't support out-of-bounds requests */ + if ((ppage_paddr < physmem_base) || (ppage_paddr >= physmem_top)) + return NULL; + + return physical_page_descr_array + (ppage_paddr >> SOS_PAGE_SHIFT); +} + + +sos_ret_t sos_physmem_ref_physpage_at(sos_paddr_t ppage_paddr) +{ + struct physical_page_descr *ppage_descr + = get_page_descr_at_paddr(ppage_paddr); + + if (! ppage_descr) + return -SOS_EINVAL; + + /* Increment the reference count for the page */ + ppage_descr->ref_cnt ++; + + /* If the page is newly referenced (ie we are the only owners of the + page => ref cnt == 1), transfer it in the used pages list */ + if (ppage_descr->ref_cnt == 1) + { + list_delete(free_ppage, ppage_descr); + list_add_tail(used_ppage, ppage_descr); + physmem_used_pages ++; + + /* The page is newly referenced */ + return FALSE; + } + + /* The page was already referenced by someone */ + return TRUE; +} + + +sos_ret_t +sos_physmem_unref_physpage(sos_paddr_t ppage_paddr) +{ + /* By default the return value indicates that the page is still + used */ + sos_ret_t retval = FALSE; + + struct physical_page_descr *ppage_descr + = get_page_descr_at_paddr(ppage_paddr); + + if (! ppage_descr) + return -SOS_EINVAL; + + /* Don't do anything if the page is not in the used list */ + if (ppage_descr->ref_cnt <= 0) + return -SOS_EINVAL; + + /* Unreference the page, and, when no mapping is active anymore, put + the page in the free list */ + ppage_descr->ref_cnt--; + if (ppage_descr->ref_cnt <= 0) + { + /* Transfer the page, considered USED, to the free list */ + list_delete(used_ppage, ppage_descr); + physmem_used_pages --; + list_add_head(free_ppage, ppage_descr); + + /* Indicate that the page is now unreferenced */ + retval = TRUE; + } + + return retval; +} diff --git a/sos-code-article4/sos/physmem.h b/sos-code-article4/sos/physmem.h new file mode 100644 index 0000000..8b5d997 --- /dev/null +++ b/sos-code-article4/sos/physmem.h @@ -0,0 +1,119 @@ +/* Copyright (C) 2004 David Decotigny + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_PHYSMEM_H_ +#define _SOS_PHYSMEM_H_ + +/** + * @file physmem.h + * + * Physical pages of memory + */ + +#include <sos/errno.h> +#include <sos/types.h> +#include <sos/macros.h> + +/** The size of a physical page (arch-dependent) */ +#define SOS_PAGE_SIZE (4*1024) + +/** The corresponding shift */ +#define SOS_PAGE_SHIFT 12 /* 4 kB = 2^12 B */ + +/** The corresponding mask */ +#define SOS_PAGE_MASK ((1<<12) - 1) + +#define SOS_PAGE_ALIGN_INF(val) \ + SOS_ALIGN_INF((val), SOS_PAGE_SIZE) +#define SOS_PAGE_ALIGN_SUP(val) \ + SOS_ALIGN_SUP((val), SOS_PAGE_SIZE) + + +/** + * This is the reserved physical interval for the x86 video memory and + * BIOS area. In physmem.c, we have to mark this area as "used" in + * order to prevent from allocating it. And in paging.c, we'd better + * map it in virtual space if we really want to be able to print to + * the screen (for debugging purpose, at least): for this, the + * simplest is to identity-map this area in virtual space (note + * however that this mapping could also be non-identical). + */ +#define BIOS_N_VIDEO_START 0xa0000 +#define BIOS_N_VIDEO_END 0x100000 + + +/** + * Initialize the physical memory subsystem, for the physical area [0, + * ram_size). This routine takes into account the BIOS and video + * areas, to prevent them from future allocations. + * + * @param ram_size The size of the RAM that will be managed by this subsystem + * + * @param kernel_core_base The lowest address for which the kernel + * assumes identity mapping (ie virtual address == physical address) + * will be stored here + * + * @param kernel_core_top The top address for which the kernel + * assumes identity mapping (ie virtual address == physical address) + * will be stored here + */ +sos_ret_t sos_physmem_setup(sos_size_t ram_size, + /* out */sos_paddr_t *kernel_core_base, + /* out */sos_paddr_t *kernel_core_top); + +/** + * Retrieve the total number of pages, and the number of free pages + */ +sos_ret_t sos_physmem_get_state(/* out */sos_count_t *total_ppages, + /* out */sos_count_t *used_ppages); + + +/** + * Get a free page. + * + * @return The (physical) address of the (physical) page allocated, or + * NULL when none currently available. + * + * @param can_block TRUE if the function is allowed to block + * @note The page returned has a reference count equal to 1. + */ +sos_paddr_t sos_physmem_ref_physpage_new(sos_bool_t can_block); + + +/** + * Increment the reference count of a given physical page. Useful for + * VM code which tries to map a precise physical address. + * + * @return TRUE when the page was previously in use, FALSE when the + * page was previously in the free list, <0 when the page address is + * invalid. + */ +sos_ret_t sos_physmem_ref_physpage_at(sos_paddr_t ppage_paddr); + + +/** + * Decrement the reference count of the given physical page. When this + * reference count reaches 0, the page is marked free, ie is available + * for future sos_physmem_get_physpage() + * + * @return FALSE when the page is still in use, TRUE when the page is now + * unreferenced, <0 when the page address is invalid + */ +sos_ret_t sos_physmem_unref_physpage(sos_paddr_t ppage_paddr); + + +#endif /* _SOS_PHYSMEM_H_ */ diff --git a/sos-code-article4/sos/types.h b/sos-code-article4/sos/types.h new file mode 100644 index 0000000..02d9f6d --- /dev/null +++ b/sos-code-article4/sos/types.h @@ -0,0 +1,50 @@ +/* Copyright (C) 2004 The SOS Team + Copyright (C) 1999 Free Software Foundation, Inc. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ +#ifndef _SOS_TYPES_H_ +#define _SOS_TYPES_H_ + +/** + * @file types.h + * + * SOS basic types definition + */ + +/** Physical address */ +typedef unsigned int sos_paddr_t; + +/** Generic virtual address (kernel or user) */ +typedef unsigned int sos_vaddr_t; + +/** Memory size of an object (positive) */ +typedef unsigned int sos_size_t; +/** Generic count of objects */ +typedef unsigned int sos_count_t; + +/** Low-level sizes */ +typedef unsigned long int sos_ui32_t; /* 32b unsigned */ +typedef unsigned short int sos_ui16_t; /* 16b unsigned */ +typedef unsigned char sos_ui8_t; /* 8b unsigned */ + +typedef enum { FALSE=0, TRUE } sos_bool_t; + +/** Not a proper type, but highly useful with basic type + manipulations */ +#define NULL ((void*)0) + +#endif /* _SOS_TYPES_H_ */ diff --git a/sos-code-article4/support/build_image.sh b/sos-code-article4/support/build_image.sh new file mode 100755 index 0000000..43929cd --- /dev/null +++ b/sos-code-article4/support/build_image.sh @@ -0,0 +1,215 @@ +#!/bin/sh +# Copyright (C) 2003, David Decotigny + +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# 1) What does it do ? +# +# 1) Check where Grub is installed (lookup_grub) +# 2) Assign some local variables using the shell script arguments. +# a) Argument 1 : the destination (either a file or a drive, like a:) +# b) Argument 2 : the loader (i.e kernel) +# c) Argument 3 : options passed to the loader +# d) Argument 4 : the modules (that can be loaded optionally by Grub) +# 3) Test whether destination is a drive or a file +# 4) Create the directory structure inside the drive +# 5) Copy the loader in the drive +# 6) Generate the 'menu.txt' file used by Grub to generate the boot menu +# 7) Copy all modules +# 8) Copy the menu.txt file +# +# 2) Why is it so complex ? +# Because it must support various Grub/mtools installations and versions +# +# In fact, this shell script is used in the KOS (kos.enix.org) +# project. This operating system consists in a loader and many many +# modules that are linked together at boot time. It is much more +# complex that a simple monolithic kernel. +# +# For your simple monolithic kernel, you only need to give argument 1 +# and 2. + +print_usage () { + echo "Usage: $0 [X:|image] path/to/loader option path/to/modules..." + echo " where X: is a valid floppy drive on your computer" + echo " where image is any file name" + exit 1 +} + +grub_dirs_common="/usr/local/share/grub/i386-freebsd /usr/local/share/grub/i386-pc /usr/share/grub/i386-pc /usr/lib/grub/i386-pc /usr/local/grub /usr/share/grub/i386-redhat /usr/local/src/grub-0.5.94 $HOME/share/grub/i386-pc/" +sbin_grub_path="/usr/local/sbin /usr/sbin /sbin $HOME/sbin" + +PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin +export PATH + +MTOOLSRC=mtoolsrc +export MTOOLSRC + +# Redefined variables +FLOPPY_DRIVE=A: +IMG_FNAME=fd.img + +## +## Format disk image +## +init_image () { + echo "Initialize disk image $IMG_FILE..." + if [ ! -f $IMG_FNAME ] ; then + dd if=/dev/zero of=$IMG_FNAME bs=18k count=80 1>/dev/null 2>&1 + fi + + rm -f $MTOOLSRC + echo "drive u: file=\"$IMG_FNAME\" 1.44M filter" > $MTOOLSRC + + if mformat U: ; then : ; else + rm -f $MTOOLSRC + echo "drive u: file=\"$IMG_FNAME\" 1.44M" > $MTOOLSRC + if mformat U: ; then : ; else + rm -f $MTOOLSRC + echo "drive u: file=\"$IMG_FNAME\"" > $MTOOLSRC + mformat U: + fi + fi +} + + +## +## Format (real) floppy disk +## +init_floppy () { + echo "Formatting floppy..." + mformat $FLOPPY_DRIVE || exit 1 +} + + +lookup_grub () { + # Look for a correct GRUBDIR + for d in $grub_dirs_common ; do + if [ -d $d ] ; then + GRUBDIR=$d + break + fi + done + + # Try to guess with locate + if [ ! -d "$GRUBDIR" ] ; then + GRUBDIR=`locate stage2 | head -1 | xargs dirname 2>/dev/null` + fi + + # Look for a correct sbin/grub + for d in $sbin_grub_path ; do + if [ -x $d/grub ] ; then + SBIN_GRUB=$d/grub + break + fi + done + + if [ -d "$GRUBDIR" -a -x "$SBIN_GRUB" ] ; then + echo "Found correct grub installation in $GRUBDIR" + echo "Found correct /sbin/grub at $SBIN_GRUB" + else + echo "Couldn't find a correct grub installation." + exit 1 + fi +} + +## +## setup_disk [drive] +## => setup disk directory structure / copy files +## +setup_disk () { + echo "Setup destination disk..." + + mmd $1/boot + mmd $1/boot/grub + + if [ -d $GRUBDIR/stage1 ] ; then + mcopy $GRUBDIR/stage1/stage1 $1/boot/grub/ + mcopy $GRUBDIR/stage2/stage2 $1/boot/grub/ + else + mcopy $GRUBDIR/stage1 $1/boot/grub/ + mcopy $GRUBDIR/stage2 $1/boot/grub/ + fi + mmd $1/system + mmd $1/modules + + $SBIN_GRUB --batch <<EOT 1>/dev/null 2>/dev/null || exit 1 +device (fd0) $IMG_FNAME +install (fd0)/boot/grub/stage1 (fd0) (fd0)/boot/grub/stage2 p (fd0)/boot/grub/menu.txt +quit +EOT +} + + + +################################################# +## Real start +## +#[ "$#" -lt 3 ] && print_usage + +lookup_grub + +dest="$1" ; shift +loader_fname="$1" ; shift +options="$1" ; shift +modules="$*" + +# Init destination disk +case x$dest in + x*:) + drive=$dest + IMG_FNAME=$dest + FLOPPY_DRIVE=$dest + init_floppy + ;; + x*) + drive=U: + IMG_FNAME=$dest + init_image + ;; +esac + +# Create directory structure +setup_disk $drive + +# Copy the loader +mcopy -bo $loader_fname $drive/system/`basename $loader_fname` + +# Generate the menu.txt file +rm -f menu.txt +cat <<EOF > menu.txt +timeout 0 +default 0 +title Simple OS +root (fd0) +kernel /system/`basename $loader_fname` $options +EOF + +# Copy the modules +for f in $modules ; do + if [ ! -f $f ] ; then + echo "ERROR: module $f not correctly compiled in." + exit 1 + fi + if ! mcopy -bo $f $drive/modules/`basename $f` ; then + echo "ERROR: module $f could not be transferred to floppy." + exit 1 + fi + echo module /modules/`basename $f` >> menu.txt +done + +# Transfers the menu.txt file to floppy +mcopy -bo menu.txt $drive/boot/grub/ diff --git a/sos-code-article4/support/sos.lds b/sos-code-article4/support/sos.lds new file mode 100644 index 0000000..4d87061 --- /dev/null +++ b/sos-code-article4/support/sos.lds @@ -0,0 +1,107 @@ +/* Copyright (C) 2003, Thomas Petazzoni + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +/* We generate binary in the ELF format */ +OUTPUT_FORMAT("elf32-i386","elf32-i386","elf32-i386"); + +/* The entry point is _start (defined in boot.S) */ +ENTRY(_start) + +/* The architecture is i386 */ +OUTPUT_ARCH("i386") + +SECTIONS +{ + /* our kernel is loaded at 0x200000 */ + . = 0x200000; + __b_load = .; + + /* the multiboot header MUST come early enough in the output + object file */ + .multiboot : + { + /* The multiboot section (containing the multiboot header) + goes here */ + *(.multiboot); + + /* + * With the following line, we force this section to be + * allocated in the output file as soon as possible, no matter + * when the file containing the multiboot header (multiboot.S) + * is compiled. This is to conform to the multiboot spec, which + * says "The Multiboot header must be contained completely + * within the first 8192 bytes of the OS image, and must be + * longword (32-bit) aligned." + */ + LONG(0); + } + + /* Defines a symbol '__b_kernel to mark the start of the kernel + code/data */ + . = ALIGN(4096); + __b_kernel = .; + + /* Beginning of the text section */ + .text ALIGN(4096) : + { + /* This section includes the code */ + *(.text*) + /* Defines the 'etext' and '_etext' at the end */ + PROVIDE(etext = .); + PROVIDE(_etext = .); + } + + /* Beginning of the data section */ + .data . : + { *(.data*) + PROVIDE(edata = .); + PROVIDE(_edata = .); + } + + /* Beginning of the read-only data section */ + .rodata . : + { *(.rodata*) + PROVIDE(erodata = .); + PROVIDE(_erodata = .); + } + /* We take note of the end of the data to load */ + __e_load = .; + + /* Beginning of the BSS section (global uninitialized data) */ + .bss SIZEOF(.rodata) + ADDR(.rodata) : + { *(.bss) + *(COMMON) + PROVIDE(ebss = .); + PROVIDE(_ebss = .); + } + + /* We take note of the end of the kernel */ + __e_kernel = .; + + /* We don't care of the note, indent, comment, etc.. sections + generated by gcc */ + /DISCARD/ :{ + *(.note*) + *(.indent) + *(.comment) + *(.stab) + *(.stabstr) + } + +} + |