Repository: hurley25/Hurlex-II Branch: master Commit: 9318f3401a37 Files: 83 Total size: 242.1 KB Directory structure: gitextract_hd27az2o/ ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── arch/ │ ├── i386/ │ │ ├── debug/ │ │ │ └── debug.c │ │ ├── driver/ │ │ │ ├── clock.c │ │ │ ├── clock.h │ │ │ ├── console.c │ │ │ ├── console.h │ │ │ ├── pic.c │ │ │ └── pic.h │ │ ├── include/ │ │ │ ├── arch.h │ │ │ ├── atomic.h │ │ │ ├── common.h │ │ │ └── spinlock.h │ │ ├── init/ │ │ │ ├── arch_init.c │ │ │ ├── init.c │ │ │ └── init_s.s │ │ ├── intr/ │ │ │ ├── intr.c │ │ │ ├── intr.h │ │ │ └── intr_s.s │ │ ├── mm/ │ │ │ ├── fault.c │ │ │ ├── gdt.c │ │ │ ├── gdt.h │ │ │ ├── gdt_s.s │ │ │ ├── pmm.c │ │ │ ├── pmm.h │ │ │ ├── vmm.c │ │ │ └── vmm.h │ │ ├── syscall/ │ │ │ ├── syscall.c │ │ │ └── syscall.h │ │ └── task/ │ │ ├── entry.s │ │ ├── switch_to.s │ │ ├── task.c │ │ └── task.h │ └── x64/ │ └── TODO ├── driver/ │ ├── block_dev.c │ ├── char_dev.c │ ├── device.c │ ├── ide.c │ └── kboard.c ├── fs/ │ ├── fs.c │ ├── mbr.c │ ├── ramfs/ │ │ └── ramfs.c │ ├── sfs/ │ │ ├── sfs.c │ │ └── sfs.h │ └── vfs.c ├── include/ │ ├── block_dev.h │ ├── char_dev.h │ ├── debug.h │ ├── device.h │ ├── elf.h │ ├── errno.h │ ├── fs.h │ ├── init.h │ ├── kio.h │ ├── lib/ │ │ ├── list.h │ │ ├── rbtree.h │ │ └── string.h │ ├── mboot.h │ ├── mbr.h │ ├── mm/ │ │ ├── buddy_mm.h │ │ ├── ff_mm.h │ │ ├── mm.h │ │ └── slob.h │ ├── sched.h │ ├── sync.h │ ├── types.h │ └── vargs.h ├── init/ │ └── kmain.c ├── isodir/ │ └── boot/ │ └── grub/ │ └── grub.cfg ├── kernel/ │ ├── errno.c │ ├── kio.c │ ├── printk.c │ └── sched/ │ └── sched.c ├── lib/ │ ├── rbtree.c │ └── string.c ├── mm/ │ ├── buddy_mm.c │ ├── ff_mm.c │ ├── mm.c │ └── slob.c └── scripts/ ├── gdbinit └── kernel.ld ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Object files *.o *.ko *.obj *.elf .clang_complete # Precompiled Headers *.gch *.pch # Libraries *.lib *.a *.la *.lo # Shared objects (inc. Windows DLLs) *.dll *.so *.so.* *.dylib # Executables *.exe *.out *.app *.i*86 *.x86_64 *.hex # The Program files *.img hx_kernel tags *.iso ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser 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. {description} Copyright (C) {year} {fullname} This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. {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 Lesser General Public License instead of this License. ================================================ FILE: Makefile ================================================ #!Makefile # -------------------------------------------------------- # # hurlex 这个小内核的 Makefile # # 默认使用的C语言编译器是 GCC、汇编语言编译器是 nasm # # qianyi.lh 2014/11/04 12:08:13 # -------------------------------------------------------- C_SOURCES = $(shell find . -name "*.c") C_OBJECTS = $(patsubst %.c, %.o, $(C_SOURCES)) S_SOURCES = $(shell find . -name "*.s") S_OBJECTS = $(patsubst %.s, %.o, $(S_SOURCES)) CC = gcc LD = ld ASM = nasm C_FLAGS = -std=c99 -c -m32 -Wall -Wextra -ggdb -gstabs+ -ffreestanding \ -I. -Iinclude -Iarch/i386 -Iarch/i386/include -fno-stack-protector LD_FLAGS = -T scripts/kernel.ld -nostdlib -m elf_i386 ASM_FLAGS = -f elf -g -F stabs all: $(S_OBJECTS) $(C_OBJECTS) link update_fd # The automatic variable `$<' is just the first prerequisite .c.o: @echo 编译代码文件 $< ... $(CC) $(C_FLAGS) $< -o $@ .s.o: @echo 编译汇编文件 $< ... $(ASM) $(ASM_FLAGS) $< link: @echo 链接内核文件... $(LD) $(LD_FLAGS) $(S_OBJECTS) $(C_OBJECTS) -o hx_kernel .PHONY:clean clean: $(RM) $(S_OBJECTS) $(C_OBJECTS) hx_kernel .PHONY:update_fd update_fd: sudo mount floppy.img /mnt/kernel sudo cp hx_kernel /mnt/kernel/hx_kernel sleep 1 sudo umount /mnt/kernel .PHONY:mount_image mount_image: sudo mount floppy.img /mnt/kernel .PHONY:umount_image umount_image: sudo umount /mnt/kernel .PHONY:iso iso: cp hx_kernel isodir/boot/ grub2-mkrescue -o hurlex.iso isodir .PHONY:runiso runiso: qemu -m 128 -hda disk.img -cdrom hurlex.iso -boot d .PHONY:runfd runfd: qemu -m 128 -hda disk.img -fda floppy.img -boot a .PHONY:qemu qemu: qemu -m 128 -hda disk.img -kernel hx_kernel .PHONY:debug debug: qemu -S -s -m 128 -hda disk.img -fda floppy.img -boot a & sleep 1 cgdb -x scripts/gdbinit .PHONY:code_line_count code_line_count: find . -type f -name "*.[c|h|s]" -exec cat {} \; | wc -l ================================================ FILE: README.md ================================================ Hurlex II ====== 一个运行在x86-IA32架构下的小内核,仅作为操作系统理论学习的参考。 第二版重新设计和构思,参考一些优秀的实现进行补充设计和编码。 ================================================ FILE: arch/i386/debug/debug.c ================================================ /* * ===================================================================================== * * Filename: debug.c * * Description: 调试相关的函数 * * Version: 1.0 * Created: 2014年11月04日 10时54分39秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #include static elf_t kernel_elf; static void elf_from_multiboot(multiboot_t *mb); static void print_stack_trace(); static const char *elf_lookup_symbol(uint32_t addr, elf_t *elf); void debug_init(void) { // 从 GRUB 提供的信息中获取到内核符号表和代码地址信息 elf_from_multiboot(glb_mboot_ptr); } static void elf_from_multiboot(multiboot_t *mb) { elf_section_header_t *sh = (elf_section_header_t *)(mb->addr); uint32_t shstrtab = sh[mb->shndx].addr; for (uint32_t i = 0; i < mb->num; i++) { const char *name = (const char *)(shstrtab + sh[i].name) + PAGE_OFFSET; // 在 GRUB 提供的 multiboot 信息中寻找内核 ELF 格式所提取的字符串表和符号表 if (strcmp(name, ".strtab") == 0) { kernel_elf.strtab = (const char *)sh[i].addr + PAGE_OFFSET; kernel_elf.strtabsz = sh[i].size; } if (strcmp(name, ".symtab") == 0) { kernel_elf.symtab = (elf_symbol_t *)(sh[i].addr + PAGE_OFFSET); kernel_elf.symtabsz = sh[i].size; } } } void panic(const char *msg) { printk("*** System panic: %s\n", msg); print_stack_trace(); printk("***\n"); // 致命错误发生后打印栈信息后停止在这里 while(1) { cpu_hlt(); } } void print_stack_trace(void) { uint32_t *ebp, *eip; __asm__ volatile ("mov %%ebp, %0" : "=r" (ebp)); while (ebp) { eip = ebp + 1; printk(" [0x%x] %s\n", *eip, elf_lookup_symbol(*eip, &kernel_elf)); ebp = (uint32_t*)*ebp; } } static const char *elf_lookup_symbol(uint32_t addr, elf_t *elf) { for (uint32_t i = 0; i < (elf->symtabsz / sizeof(elf_symbol_t)); i++) { if (ELF32_ST_TYPE(elf->symtab[i].info) != 0x2) { continue; } // 通过函数调用地址查到函数的名字(地址在该函数的代码段地址区间之内) if ( (addr >= elf->symtab[i].value) && (addr < (elf->symtab[i].value + elf->symtab[i].size)) ) { return (const char *)((uint32_t)elf->strtab + elf->symtab[i].name); } } return NULL; } void print_cur_status(void) { static int round = 0; uint16_t reg1, reg2, reg3, reg4; __asm__ volatile ( "mov %%cs, %0;" "mov %%ds, %1;" "mov %%es, %2;" "mov %%ss, %3;" : "=m"(reg1), "=m"(reg2), "=m"(reg3), "=m"(reg4)); // 打印当前的运行级别 printk("%d: @ring %d\n", round, reg1 & 0x3); printk("%d: cs = %x\n", round, reg1); printk("%d: ds = %x\n", round, reg2); printk("%d: es = %x\n", round, reg3); printk("%d: ss = %x\n", round, reg4); ++round; } void show_memory_map(void) { uint32_t mmap_addr = glb_mboot_ptr->mmap_addr; uint32_t mmap_length = glb_mboot_ptr->mmap_length; printk("Memory map:\n\n"); mmap_entry_t *mmap = (mmap_entry_t *)mmap_addr; for (mmap = (mmap_entry_t *)mmap_addr; (uint32_t)mmap < mmap_addr + mmap_length; mmap++) { printk("base_addr = 0x%X%08X, length = 0x%X%08X, type = 0x%X\n", (uint32_t)mmap->base_addr_high, (uint32_t)mmap->base_addr_low, (uint32_t)mmap->length_high, (uint32_t)mmap->length_low, (uint32_t)mmap->type); } printk("\n"); } void show_kernel_memory_map(void) { printk("kernel in memory start: 0x%08X\n", kern_start); printk("kernel in memory end: 0x%08X\n", kern_end); printk("\nkernel segment in memory:\n"); printk(" .init.text 0x%08X ~ 0x%08X \n", kern_init_text_start, kern_init_text_end); printk(" .init.data 0x%08X ~ 0x%08X \n", kern_init_data_start, kern_init_data_end); printk(" .text 0x%08X ~ 0x%08X \n", kern_text_start, kern_text_end); printk(" .data 0x%08X ~ 0x%08X \n", kern_data_start, kern_data_end); printk("\nkernel in memory used: %d KB = %d Pages\n\n", (kern_end - kern_start) / 1024, (kern_end - kern_start) / 1024 / 4); } ================================================ FILE: arch/i386/driver/clock.c ================================================ /* * ===================================================================================== * * Filename: clock.c * * Description: 定时中断函数 * * Version: 1.0 * Created: 2014年11月04日 14时58分12秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #include "clock.h" #define FREQUENCY 100 // 定时中断由 8253/8254 芯片从 IRQ0 提供 #define IO_TIMER 0x040 // 8253 Timer #1 // 输入频率为 1193180,frequency 即每秒中断次数 #define TIMER_FREQ 1193180 // Intel 8253/8254 PIT芯片 I/O端口地址范围是40h~43h #define TIMER_MODE (IO_TIMER + 3) // timer mode port #define TIMER_SEL0 0x00 // select counter 0 #define TIMER_RATEGEN 0x04 // mode 2 #define TIMER_CLK 0x06 // mode 3 #define TIMER_16BIT 0x30 // r/w counter 16 bits, LSB first void clock_init(void) { // 注册时间相关的处理函数 register_interrupt_handler(IRQ0, clock_callback); uint32_t divisor = TIMER_FREQ / FREQUENCY; outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); // 拆分低字节和高字节 uint8_t low = (uint8_t)(divisor & 0xFF); uint8_t hign = (uint8_t)((divisor >> 8) & 0xFF); // 分别写入低字节和高字节 outb(IO_TIMER, low); outb(IO_TIMER, hign); } ================================================ FILE: arch/i386/driver/clock.h ================================================ /* * ===================================================================================== * * Filename: clock.h * * Description: 定时中断相关 * * Version: 1.0 * Created: 2014年11月04日 15时01分16秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_TIMER_H_ #define INCLUDE_TIMER_H_ #include void clock_init(void); #endif // INCLUDE_TIMER_H_ ================================================ FILE: arch/i386/driver/console.c ================================================ /* * ===================================================================================== * * Filename: console.c * * Description: 80 * 25 显示模式驱动程序 * * Version: 1.0 * Created: 2014年11月04日 10时44分26秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #include "console.h" /* * VGA(Video Graphics Array,视频图形阵列)是使用模拟信号的一种视频传输标准, * 内核可以通过它来控制屏幕上字符或者图形的显示。 * 在默认的文本模式(Text-Mode)下,VGA控制器保留了一块内存(0x8b000~0x8bfa0) * 作为屏幕上字符显示的缓冲区,若要改变屏幕上字符的显示,只需要修改这块内存就好了。 */ // VGA 的显示缓冲的起点是 0xB8000 static uint16_t *video_memory = (uint16_t *)(0xB8000 + PAGE_OFFSET); // 屏幕"光标"的坐标 static uint16_t cursor_x = 0; static uint16_t cursor_y = 0; // 屏幕是 80 * 25 #define CON_WIDTH 80 #define CON_HIGH 25 // VGA内存输入缓冲区 80 * 128 #define BUFF_WIDTH 80 #define BUFF_HIGH 128 // VGA 输出缓冲区 static uint16_t video_buffer[BUFF_WIDTH * BUFF_HIGH]; // buffer 输出的坐标 static uint16_t buffer_x = 0; static uint16_t buffer_y = 0; // 当前屏幕显示在缓冲区的起始位置 static uint16_t current_line = 0; // VGA 内部的寄存器多达300多个,显然无法一一映射到I/O端口的地址空间。 // 对此 VGA 控制器的解决方案是,将一个端口作为内部寄存器的索引:0x3D4, // 再通过 0x3D5 端口来设置相应寄存器的值。 #define VGA_IDX 0x3D4 #define VGA_SET 0x3D5 // 在这里用到的两个内部寄存器的编号为0xE与0xF,分别表示光标位置的高8位与低8位。 #define CUR_HIGH 0xE #define CUR_LOW 0xF // 移动光标 static void move_cursor(void); // 刷新屏幕显示到当前输出位置 static void _flush_console_current(void); // 屏幕显示初始化 void console_init(void) { console_clear(); cprintk(rc_black, rc_green, "Hello, Hurlex II kernel!\n\n"); } // 清屏操作 void console_clear(void) { uint8_t attribute_byte = (0 << 4) | (15 & 0x0F); uint16_t blank = 0x20 | (attribute_byte << 8); // 初始化 console 数据 for (uint32_t i = 0; i < CON_WIDTH * CON_HIGH; ++i) { video_memory[i] = blank; } cursor_x = 0; cursor_y = 0; move_cursor(); // 初始化 buffer 数据 for (uint32_t i = 0; i < BUFF_WIDTH * BUFF_HIGH; ++i) { video_buffer[i] = blank; } buffer_x = 0; buffer_y = 0; current_line = 0; } // 移动光标 static void move_cursor(void) { uint16_t cursor = cursor_y * CON_WIDTH + cursor_x; outb(VGA_IDX, CUR_HIGH); // 告诉 VGA 我们要设置光标的高字节 outb(VGA_SET, (cursor >> 8) & 0xFF); // 发送高 8 位 outb(VGA_IDX, CUR_LOW); // 告诉 VGA 我们要设置光标的低字节 outb(VGA_SET, cursor & 0xFF); // 发送低 8 位 } // 滚动缓冲区 static void scroll_buffer(void) { // attribute_byte 被构造出一个黑底白字的描述格式 uint8_t attribute_byte = (0 << 4) | (15 & 0x0F); uint16_t blank = 0x20 | (attribute_byte << 8); // space 是 0x20 // buffer_y 到 BUFF_HIGH - 1 的时候,就该换行了 if (buffer_y == BUFF_HIGH - 1) { // 将所有行的显示数据复制到上一行,第一行永远消失了... for (uint32_t i = 0 * BUFF_WIDTH; i < (BUFF_HIGH-1) * BUFF_WIDTH; i++) { video_buffer[i] = video_buffer[i+BUFF_WIDTH]; } // 最后的一行数据现在填充空格,不显示任何字符 for (uint32_t i = (BUFF_HIGH-1) * BUFF_WIDTH; i < BUFF_HIGH * BUFF_WIDTH; i++) { video_buffer[i] = blank; } buffer_y--; } } // 屏幕输出一个字符(带颜色) static void console_putc_color(char c, real_color_t back, real_color_t fore) { uint8_t back_color = (uint8_t)back; uint8_t fore_color = (uint8_t)fore; uint8_t attribute_byte = (back_color << 4) | (fore_color & 0x0F); uint16_t attribute = attribute_byte << 8; // 0x08 是 退格键 的 ASCII 码 // 0x09 是 tab 键 的 ASCII 码 if (c == 0x08 && buffer_x) { buffer_x--; } else if (c == 0x09) { buffer_x = (buffer_x+8) & ~(8-1); } else if (c == '\r') { buffer_x = 0; } else if (c == '\n') { buffer_x = 0; buffer_y++; } else if (c >= ' ') { video_buffer[buffer_y * BUFF_WIDTH + buffer_x] = c | attribute; buffer_x++; } // 每 80 个字符一行,满80就必须换行了 if (buffer_x == BUFF_WIDTH) { buffer_x = 0; buffer_y ++; } // 滚动缓冲区 scroll_buffer(); } // 屏幕打印一个以 \0 结尾的字符串(默认黑底白字) void console_write(char *cstr) { bool intr_flag = false; local_intr_store(intr_flag); { while (*cstr) { console_putc_color(*cstr++, rc_black, rc_white); } _flush_console_current(); } local_intr_restore(intr_flag); } // 屏幕打印一个以 \0 结尾的字符串(带颜色) void console_write_color(char *cstr, real_color_t back, real_color_t fore) { bool intr_flag = false; local_intr_store(intr_flag); { while (*cstr) { console_putc_color(*cstr++, back, fore); } _flush_console_current(); } local_intr_restore(intr_flag); } // 刷新屏幕显示到指定位置 static void _flush_console(void) { uint8_t attribute_byte = (0 << 4) | (15 & 0x0F); uint16_t blank = 0x20 | (attribute_byte << 8); uint16_t begin_line = 0, end_line = 0; begin_line = current_line; end_line = buffer_y + 1; uint32_t i = 0; for (uint32_t j = begin_line * CON_WIDTH; j < end_line * CON_WIDTH; ++j) { video_memory[i] = video_buffer[j]; i++; } while (i < CON_WIDTH * CON_HIGH) { video_memory[i] = blank; i++; } cursor_x = buffer_x; cursor_y = end_line - begin_line - 1; move_cursor(); } // 刷新屏幕显示到当前输出位置 static void _flush_console_current(void) { if (buffer_y >= CON_HIGH - 1) { current_line = buffer_y - CON_HIGH + 1; } else { current_line = 0; } _flush_console(); } // 屏幕显示向上移动n行 void console_view_up(uint16_t offset) { if (current_line >= offset) { current_line -= offset; } else { current_line = 0; } _flush_console(); } // 屏幕显示向下移动n行 void console_view_down(uint16_t offset) { if (current_line + offset < buffer_y) { current_line += offset; } else { current_line = buffer_y; } _flush_console(); } ================================================ FILE: arch/i386/driver/console.h ================================================ /* * ===================================================================================== * * Filename: console.h * * Description: 屏幕输出函数 * * Version: 1.0 * Created: 2014年11月04日 10时49分13秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_CONSOLE_H_ #define INCLUDE_CONSOLE_H_ #include typedef enum real_color { rc_black = 0, rc_blue = 1, rc_green = 2, rc_cyan = 3, rc_red = 4, rc_magenta = 5, rc_brown = 6, rc_light_grey = 7, rc_dark_grey = 8, rc_light_blue = 9, rc_light_green = 10, rc_light_cyan = 11, rc_light_red = 12, rc_light_magenta = 13, rc_light_brown = 14, rc_white = 15 } real_color_t; // 屏幕显示初始化 void console_init(void); // 清屏操作 void console_clear(void); // 屏幕打印一个以 \0 结尾的字符串(默认黑底白字) void console_write(char *cstr); // 屏幕打印一个以 \0 结尾的字符串(带颜色) void console_write_color(char *cstr, real_color_t back, real_color_t fore); // 屏幕显示向上移动n行 void console_view_up(uint16_t offset); // 屏幕显示向下移动n行 void console_view_down(uint16_t offset); #endif // INCLUDE_CONSOLE_H_ ================================================ FILE: arch/i386/driver/pic.c ================================================ /* * ===================================================================================== * * Filename: pic.c * * Description: PIC 相关 * * Version: 1.0 * Created: 2014年11月06日 09时48分25秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include "pic.h" #define IO_PIC1 (0x20) // Master (IRQs 0-7) #define IO_PIC2 (0xA0) // Slave (IRQs 8-15) #define IO_PIC1C (IO_PIC1+1) #define IO_PIC2C (IO_PIC2+1) // 设置 8259A 芯片 void init_interrupt_chip(void) { // 重新映射 IRQ 表 // 两片级联的 Intel 8259A 芯片 // 主片端口 0x20 0x21 // 从片端口 0xA0 0xA1 // 初始化主片、从片 // 0001 0001 outb(IO_PIC1, 0x11); outb(IO_PIC2, 0x11); // 设置主片 IRQ 从 0x20(32) 号中断开始 outb(IO_PIC1C, 0x20); // 设置从片 IRQ 从 0x28(40) 号中断开始 outb(IO_PIC2C, 0x28); // 设置主片 IR2 引脚连接从片 outb(IO_PIC1C, 0x04); // 告诉从片输出引脚和主片 IR2 号相连 outb(IO_PIC2C, 0x02); // 设置主片和从片按照 8086 的方式工作 outb(IO_PIC1C, 0x01); outb(IO_PIC2C, 0x01); // 设置主从片允许中断 outb(IO_PIC1C, 0x0); outb(IO_PIC2C, 0x0); } // 重设 8259A 芯片 void clear_interrupt_chip(uint32_t intr_no) { // 发送中断结束信号给 PICs // 按照我们的设置,从 32 号中断起为用户自定义中断 // 因为单片的 Intel 8259A 芯片只能处理 8 级中断 // 故大于等于 40 的中断号是由从片处理的 if (intr_no >= 40) { // 发送重设信号给从片 outb(IO_PIC2, 0x20); } // 发送重设信号给主片 outb(IO_PIC1, 0x20); } ================================================ FILE: arch/i386/driver/pic.h ================================================ /* * ===================================================================================== * * Filename: pic.h * * Description: PIC 相关 * * Version: 1.0 * Created: 2014年11月06日 09时51分59秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_PIC_H_ #define INCLUDE_PIC_H_ #include // 设置8259A芯片 void init_interrupt_chip(void); // 重设 8259A 芯片 void clear_interrupt_chip(uint32_t intr_no); #endif // INCLUDE_PIC_H_ ================================================ FILE: arch/i386/include/arch.h ================================================ /* * ===================================================================================== * * Filename: arch.h * * Description: 架构相关的头文件引用 * * Version: 1.0 * Created: 2014年11月05日 09时48分34秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef ARCH_H_ #define ARCH_H_ #include #include #include #include #include #include // 架构相关的初始化 void arch_init(void); #endif // ARCH_H_ ================================================ FILE: arch/i386/include/atomic.h ================================================ /* * ===================================================================================== * * Filename: atomic.h * * Description: 一些原子操作 * * Version: 1.0 * Created: 2014年11月08日 20时51分18秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef ATOMIC_H_ #define ATOMIC_H_ #include #define LOCK_PREFIX "lock;" #define ATOMIC_INIT(i) { (i) } static inline void set_bit(int32_t nr, volatile void *addr) { __asm__ volatile ("btsl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr)); } static inline void clear_bit(int32_t nr, volatile void *addr) { __asm__ volatile ("btrl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr)); } static inline void change_bit(int32_t nr, volatile void *addr) { __asm__ volatile ("btcl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr)); } static inline bool test_bit(int32_t nr, volatile void *addr) { int32_t oldbit; __asm__ volatile ("btl %2, %1; sbbl %0,%0" : "=r" (oldbit) : "m" (*(volatile long *)addr), "Ir" (nr)); return (oldbit != 0); } static inline int32_t atomic_read(const atomic_t *v) { return v->counter; } static inline void atomic_set(atomic_t *v, int32_t i) { v->counter = i; } static inline void atomic_add(atomic_t *v, int32_t i) { __asm__ volatile(LOCK_PREFIX "addl %1,%0" : "+m" (v->counter) : "ir" (i)); } static inline void atomic_sub(atomic_t *v, int32_t i) { __asm__ volatile(LOCK_PREFIX "subl %1,%0" : "+m" (v->counter) : "ir" (i)); } static inline int32_t atomic_sub_and_test(atomic_t *v, int32_t i) { unsigned char c; __asm__ volatile(LOCK_PREFIX "subl %2,%0; sete %1" : "+m" (v->counter), "=qm" (c) : "ir" (i) : "memory"); return c; } static inline void atomic_inc(atomic_t *v) { __asm__ volatile(LOCK_PREFIX "incl %0" : "+m" (v->counter)); } static inline int32_t atomic_inc_and_test(atomic_t *v) { unsigned char c; __asm__ volatile(LOCK_PREFIX "incl %0; sete %1" : "+m" (v->counter), "=qm" (c) : : "memory"); return (c != 0); } static inline void atomic_dec(atomic_t *v) { __asm__ volatile(LOCK_PREFIX "decl %0" : "+m" (v->counter)); } static inline int32_t atomic_dec_and_test(atomic_t *v) { unsigned char c; __asm__ volatile(LOCK_PREFIX "decl %0; sete %1" : "+m" (v->counter), "=qm" (c) : : "memory"); return (c != 0); } #endif // ATOMIC_H_ ================================================ FILE: arch/i386/include/common.h ================================================ /* * ===================================================================================== * * Filename: common.h * * Description: 杂项函数 * * Version: 1.0 * Created: 2014年11月04日 10时48分17秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_COMMON_H_ #define INCLUDE_COMMON_H_ #include "types.h" /* Eflags register */ #define FL_CF 0x00000001 // Carry Flag #define FL_PF 0x00000004 // Parity Flag #define FL_AF 0x00000010 // Auxiliary carry Flag #define FL_ZF 0x00000040 // Zero Flag #define FL_SF 0x00000080 // Sign Flag #define FL_TF 0x00000100 // Trap Flag #define FL_IF 0x00000200 // Interrupt Flag #define FL_DF 0x00000400 // Direction Flag #define FL_OF 0x00000800 // Overflow Flag #define FL_IOPL_MASK 0x00003000 // I/O Privilege Level bitmask #define FL_IOPL_0 0x00000000 // IOPL == 0 #define FL_IOPL_1 0x00001000 // IOPL == 1 #define FL_IOPL_2 0x00002000 // IOPL == 2 #define FL_IOPL_3 0x00003000 // IOPL == 3 #define FL_NT 0x00004000 // Nested Task #define FL_RF 0x00010000 // Resume Flag #define FL_VM 0x00020000 // Virtual 8086 mode #define FL_AC 0x00040000 // Alignment Check #define FL_VIF 0x00080000 // Virtual Interrupt Flag #define FL_VIP 0x00100000 // Virtual Interrupt Pending #define FL_ID 0x00200000 // ID flag #define __barrier__() __asm__ volatile ("" ::: "memory") // 端口写一个字节 static inline void outb(uint16_t port, uint8_t value) { __asm__ volatile ("outb %1, %0" : : "dN" (port), "a" (value)); } // 端口读一个字节 static inline uint8_t inb(uint16_t port) { uint8_t ret; __asm__ volatile("inb %1, %0" : "=a" (ret) : "dN" (port)); return ret; } // 端口读一个字 static inline uint16_t inw(uint16_t port) { uint16_t ret; __asm__ volatile ("inw %1, %0" : "=a" (ret) : "dN" (port)); return ret; } static inline void insl(uint32_t port, void *addr, int cnt) { __asm__ volatile ( "cld;" "repne; insl;" : "=D" (addr), "=c" (cnt) : "d" (port), "0" (addr), "1" (cnt) : "memory", "cc"); } static inline void outsl(uint32_t port, const void *addr, int cnt) { __asm__ volatile ( "cld;" "repne; outsl;" : "=S" (addr), "=c" (cnt) : "d" (port), "0" (addr), "1" (cnt) : "memory", "cc"); } // 开启中断 static inline void enable_intr(void) { __asm__ volatile ("sti"); } // 关闭中断 static inline void disable_intr(void) { __asm__ volatile ("cli" ::: "memory"); } // 执行CPU空操作 static inline void cpu_hlt(void) { __asm__ volatile ("hlt"); } // 读取 EFLAGS static inline uint32_t read_eflags(void) { uint32_t eflags; __asm__ volatile ("pushfl; popl %0" : "=r" (eflags)); return eflags; } // 写入EFALGS static inline void write_eflags(uint32_t eflags) { __asm__ volatile ("pushl %0; popfl" :: "r" (eflags)); } // 修改当前页表 static inline void switch_pgd(uint32_t pd) { __asm__ volatile ("mov %0, %%cr3" : : "r" (pd)); } // 通知 CPU 更新页表缓存 static inline void tlb_reload_page(uint32_t va) { __asm__ volatile ("invlpg (%0)" : : "a" (va)); } // 修改栈地址 static inline void load_esp(uint32_t esp) { __asm__ volatile ("mov %0, %%esp" : : "r" (esp)); } #endif // INCLUDE_COMMON_H_ ================================================ FILE: arch/i386/include/spinlock.h ================================================ /* * ===================================================================================== * * Filename: spinlock.h * * Description: 自旋锁的实现 * * Version: 1.0 * Created: 2014年11月12日 11时16分51秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_SPINLOCK_H_ #define INCLUDE_SPINLOCK_H_ #include typedef struct spinlock_t { volatile uint32_t lock; } spinlock_t; // 1 表示 spinlock 可用 #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 } // 初始化自旋锁 #define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0) // spinlock 加锁 static inline void spinlock_lock(spinlock_t *lock) { __asm__ volatile ("\n1:\t" "lock; decb %0\n\t" // decb 将 lock->lock 减 1,lock 表示要锁住地址总线 "js 2f\n\t" ".section .text.lock, \"ax\"\n" "2:\t" "cmpb $0, %0\n\t" "rep; nop\n\t" "jle 2b\n\t" "jmp 1b\n\t" ".previous" :"=m" (lock->lock) : : "memory"); } // spinlock 解锁 static inline void spinlock_unlock(spinlock_t *lock) { __asm__ volatile ("movb $1, %0" :"=m" (lock->lock) : : "memory"); } #endif // INCLUDE_SPINLOCK_H_ ================================================ FILE: arch/i386/init/arch_init.c ================================================ /* * ===================================================================================== * * Filename: arch_init.c * * Description: 体系结构相关初始化 * * Version: 1.0 * Created: 2015年02月03日 16时26分53秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include // 体系结构相关的初始化函数 void arch_init(void) { gdt_init(); idt_init(); clock_init(); console_init(); } ================================================ FILE: arch/i386/init/init.c ================================================ /* * ===================================================================================== * * Filename: init.c * * Description: 内核初始化 * * Version: 1.0 * Created: 2014年11月04日 10时03分01秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include // 开启分页机制之后的 Multiboot 数据指针 multiboot_t *glb_mboot_ptr; // 开启分页机制之后的内核栈 uint8_t kern_stack[STACK_SIZE] __attribute__ ((aligned(STACK_SIZE))); // 内核栈的栈顶 uint32_t kern_stack_top = (uint32_t)kern_stack + STACK_SIZE; // 内核使用的临时页表和页目录 // 该地址必须是页对齐的地址,内存 0-640KB 肯定是空闲的 __attribute__((section(".init.data"))) pgd_t *pgd_tmp = (pgd_t *)0x1000; __attribute__((section(".init.data"))) pte_t *pte_low = (pte_t *)0x2000; __attribute__((section(".init.data"))) pte_t *pte_hign = (pte_t *)0x3000; // 映射临时页表 __attribute__((section(".init.text"))) void mmap_tmp_page(void); // 启用分页 __attribute__((section(".init.text"))) void enable_paging(void); // 内核入口函数 __attribute__((section(".init.text"))) void kern_entry(void) { // 映射临时页表 mmap_tmp_page(); // 启用分页 enable_paging(); // 切换临时内核栈到分页后的新栈 __asm__ volatile ("mov %0, %%esp\n\t" "xor %%ebp, %%ebp" : : "r" (kern_stack_top)); // 更新全局 multiboot_t 指针指向 glb_mboot_ptr = (multiboot_t *)((uint32_t)mboot_ptr_tmp + PAGE_OFFSET); // 调用内核初始化函数 kern_init(); // 之前的函数调用链自栈切换后断开,无法再返回之前的调用点 } // 映射临时页表 __attribute__((section(".init.text"))) void mmap_tmp_page(void) { pgd_tmp[0] = (uint32_t)pte_low | PAGE_PRESENT | PAGE_WRITE; for (int i = 0; i < 4; ++i) { uint32_t pgd_idx = PGD_INDEX(PAGE_OFFSET + PAGE_MAP_SIZE * i); pgd_tmp[pgd_idx] = ((uint32_t)pte_hign + PAGE_SIZE * i) | PAGE_PRESENT | PAGE_WRITE; } // 映射内核虚拟地址 4MB 到物理地址的前 4MB // 因为 .init.text 段的代码在物理地址前 4MB 处(肯定不会超出这个范围), // 开启分页后若此处不映射,代码执行立即会出错,离开 .init.text 段后的代码执行, // 不再需要映射物理前 4MB 的内存 for (int i = 0; i < 1024; i++) { pte_low[i] = (i << 12) | PAGE_PRESENT | PAGE_WRITE; } // 映射 0x00000000-0x01000000 的物理地址到虚拟地址 0xC0000000-0xC1000000 for (int i = 0; i < 1024 * 4; i++) { pte_hign[i] = (i << 12) | PAGE_PRESENT | PAGE_WRITE; } // 设置临时页表 __asm__ volatile ("mov %0, %%cr3" : : "r" (pgd_tmp)); } // 启用分页 __attribute__((section(".init.text"))) void enable_paging(void) { uint32_t cr0; __asm__ volatile ("mov %%cr0, %0" : "=r" (cr0)); // 最高位 PG 位置 1,分页开启 cr0 |= (1u << 31); __asm__ volatile ("mov %0, %%cr0" : : "r" (cr0)); } ================================================ FILE: arch/i386/init/init_s.s ================================================ ; ---------------------------------------------------------------- ; ; init.s -- 内核从这里开始 ; ; qianyi.lh 2014/11/04 9:30:50 ; ---------------------------------------------------------------- ; 一些宏定义 MBOOT_HEADER_MAGIC equ 0x1BADB002 ; Multiboot 魔数,由规范决定的 MBOOT_PAGE_ALIGN equ 1 << 0 ; 0 号位表示所有的引导模块将按页(4KB)边界对齐 MBOOT_MEM_INFO equ 1 << 1 ; 1 号位通过 Multiboot 信息结构的 mem_* 域包括可用内存的信息 ; 定义我们使用的 Multiboot 的标记 MBOOT_HEADER_FLAGS equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO ; 域checksum是一个32位的无符号值,当与其他的magic域(也就是magic和flags)相加时, ; 要求其结果必须是32位的无符号值 0 (即magic + flags + checksum = 0) MBOOT_CHECKSUM equ - (MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS) ; ---------------------------------------------------------------- ; 符合Multiboot规范的 OS 映象需要这样一个 magic Multiboot 头 ; ---------------------------------- ; 偏移量 类型 域名 备注 ; ; 0 u32 magic 必需 ; 4 u32 flags 必需 ; 8 u32 checksum 必需 ; ---------------------------------- ; ---------------------------------------------------------------- [BITS 32] ; 所有代码以 32-bit 的方式编译 section .init.text ; 临时代码段从这里开始 ; 在代码段的起始位置定义符合 Multiboot 规范的标记 dd MBOOT_HEADER_MAGIC ; GRUB 会通过这个魔数判断该映像是否支持 dd MBOOT_HEADER_FLAGS ; GRUB 的一些加载时选项,其详细注释在定义处 dd MBOOT_CHECKSUM ; 检测数值,其含义在定义处 [GLOBAL start] ; 内核代码入口,此处提供该声明给 ld 链接器 [GLOBAL mboot_ptr_tmp] ; 全局的 struct multiboot * 变量 [EXTERN kern_entry] ; 声明内核 C 代码的入口函数 start: mov [mboot_ptr_tmp], ebx ; 将 ebx 中的指针存入 mboot_ptr_tmp mov esp, STACK_TOP ; 设置内核栈地址 and esp, 0FFFFFFF0H ; 栈地址按照 16 字节对齐 mov ebp, 0 ; 帧指针修改为 0 call kern_entry ; 调用内核入口函数 noreturn: ; 代码永远不会返回到这里 hlt jmp noreturn ;----------------------------------------------------------------------------- section .init.data ; 开启分页前临时的数据段 stack: times 1024 db 0 ; 这里作为临时内核栈 STACK_TOP equ $-stack-1 ; 内核栈顶,$ 符指代是当前地址 mboot_ptr_tmp: dd 0 ; 全局的 multiboot 结构体指针 ;----------------------------------------------------------------------------- ================================================ FILE: arch/i386/intr/intr.c ================================================ /* * ===================================================================================== * * Filename: intr.c * * Description: 中断描述符表相关 * * Version: 1.0 * Created: 2014年11月04日 14时45分36秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #define INTERRUPT_MAX 256 // 中断描述符 typedef struct idt_entry_t { uint16_t base_lo; // 中断处理函数地址 15~0 位 uint16_t sel; // 目标代码段描述符选择子 uint8_t always0; // 置 0 段 uint8_t flags; // 一些标志,文档有解释 uint16_t base_hi; // 中断处理函数地址 31~16 位 }__attribute__((packed)) idt_entry_t; // IDTR typedef struct idt_ptr_t { uint16_t limit; // 限长 uint32_t base; // 基址 } __attribute__((packed)) idt_ptr_t; // 中断描述符表 static idt_entry_t idt_entries[INTERRUPT_MAX] __attribute__ ((aligned(16))); // IDTR static idt_ptr_t idt_ptr; // 中断处理函数的指针数组 static interrupt_handler_t interrupt_handlers[INTERRUPT_MAX] __attribute__ ((aligned(4))); // 设置中断描述符 static void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags); // 声明加载 IDTR 的函数 extern void idt_flush(uint32_t); // 中断处理函数指针类型 typedef void (*isr_irq_func_t)(); // 中断处理函数指针数组 static isr_irq_func_t isr_irq_func[INTERRUPT_MAX] = { [0] = &isr0, [1] = &isr1, [2] = &isr2, [3] = &isr3, [4] = &isr4, [5] = &isr5, [6] = &isr6, [7] = &isr7, [8] = &isr8, [9] = &isr9, [10] = &isr10, [11] = &isr11, [12] = &isr12, [13] = &isr13, [14] = &isr14, [15] = &isr15, [16] = &isr16, [17] = &isr17, [18] = &isr18, [19] = &isr19, [20] = &isr20, [21] = &isr21, [22] = &isr22, [23] = &isr23, [24] = &isr24, [25] = &isr25, [26] = &isr26, [27] = &isr27, [28] = &isr28, [29] = &isr29, [30] = &isr30, [31] = &isr31, [32] = &irq0, [33] = &irq1, [34] = &irq2, [35] = &irq3, [36] = &irq4, [37] = &irq5, [38] = &irq6, [39] = &irq7, [40] = &irq8, [41] = &irq9, [42] = &irq10, [43] = &irq11, [44] = &irq12, [45] = &irq13, [46] = &irq14, [47] = &irq15, }; // 初始化中断描述符表 void idt_init(void) { init_interrupt_chip(); idt_ptr.limit = sizeof(idt_entry_t) * INTERRUPT_MAX - 1; idt_ptr.base = (uint32_t)&idt_entries; // 0~31: 用于 CPU 的中断处理 // 32~47: Intel 保留 for (uint32_t i = 0; i < 48; ++i) { idt_set_gate(i, (uint32_t)isr_irq_func[i], 0x08, 0x8E); } // 128 (0x80) 将来用于实现系统调用 idt_set_gate(128, (uint32_t)isr128, 0x08, 0xEF); // 更新设置中断描述符表 idt_flush((uint32_t)&idt_ptr); } // 设置中断描述符 static void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { idt_entries[num].base_lo = base & 0xFFFF; idt_entries[num].base_hi = (base >> 16) & 0xFFFF; idt_entries[num].sel = sel; idt_entries[num].always0 = 0; idt_entries[num].flags = flags; } static const char *intrname(uint32_t intrno) { static const char *const intrnames[] = { "Divide error", "Debug", "Non-Maskable Interrupt", "Breakpoint", "Overflow", "BOUND Range Exceeded", "Invalid Opcode", "Device Not Available", "Double Fault", "Coprocessor Segment Overrun", "Invalid TSS", "Segment Not Present", "Stack Fault", "General Protection", "Page Fault", "(unknown trap)", "x87 FPU Floating-Point Error", "Alignment Check", "Machine-Check", "SIMD Floating-Point Exception" }; if (intrno < sizeof(intrnames)/sizeof(const char *const)) { return intrnames[intrno]; } return "(unknown trap)"; } // 调用中断处理函数 void isr_handler(pt_regs_t *regs) { if (interrupt_handlers[regs->int_no]) { interrupt_handlers[regs->int_no](regs); } else { cprintk(rc_black, rc_blue, "Unhandled interrupt: %d %s\n", regs->int_no, intrname(regs->int_no)); cpu_hlt(); } } // 注册一个中断处理函数 void register_interrupt_handler(uint8_t n, interrupt_handler_t h) { interrupt_handlers[n] = h; } // IRQ 处理函数 void irq_handler(pt_regs_t *regs) { // 重设PIC芯片 clear_interrupt_chip(regs->int_no); if (interrupt_handlers[regs->int_no]) { interrupt_handlers[regs->int_no](regs); } } ================================================ FILE: arch/i386/intr/intr.h ================================================ /* * ===================================================================================== * * Filename: intr.h * * Description: 中断描述符表相关 * * Version: 1.0 * Created: 2014年11月04日 14时49分48秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef IDT_H_ #define IDT_H_ #include // 中断保存的寄存器类型 typedef struct pt_regs_t { // 用于保存用户的数据段描述符 uint16_t ds; uint16_t padding1; // 从 edi 到 eax 由 pusha 指令压栈 uint32_t edi; uint32_t esi; uint32_t ebp; uint32_t oesp; uint32_t ebx; uint32_t edx; uint32_t ecx; uint32_t eax; // 中断号(内核代码自行压栈) uint32_t int_no; // 错误代码(有中断错误代码的中断会由CPU压栈) uint32_t err_code; // 以下由处理器自动压栈 uint32_t eip; uint16_t cs; uint16_t padding2; uint32_t eflags; // 如果发生了特权级的切换CPU会压栈 uint32_t esp; uint16_t ss; uint16_t padding3; } pt_regs_t; // 定义中断处理函数指针 typedef void (*interrupt_handler_t)(pt_regs_t *); // 调用中断处理函数 void isr_handler(pt_regs_t *regs); // 注册一个中断处理函数 void register_interrupt_handler(uint8_t n, interrupt_handler_t h); // 中断号定义 #define INT_DIVIDE_ERROR 0 #define INT_DEBUG 1 #define INT_NMI 2 #define INT_BREAKPOINT 3 #define INT_OVERFLOW 4 #define INT_BOUND 5 #define INT_INVALID_OPCODE 6 #define INT_DEVICE_NOT_AVAIL 7 #define INT_DOUBLE_FAULT 8 #define INT_COPROCESSOR 9 #define INT_INVALID_TSS 10 #define INT_SEGMENT 11 #define INT_STACK_FAULT 12 #define INT_GENERAL_PROTECT 13 #define INT_PAGE_FAULT 14 #define INT_X87_FPU 16 #define INT_ALIGNMENT 17 #define INT_MACHINE_CHECK 18 #define INT_SIMD_FLOAT 19 #define INT_VIRTUAL_EXCE 20 // 声明中断处理函数 0-19 属于 CPU 的异常中断 // ISR:中断服务程序(interrupt service routine) void isr0(); // 0 #DE 除 0 异常 void isr1(); // 1 #DB 调试异常 void isr2(); // 2 NMI void isr3(); // 3 BP 断点异常 void isr4(); // 4 #OF 溢出 void isr5(); // 5 #BR 对数组的引用超出边界 void isr6(); // 6 #UD 无效或未定义的操作码 void isr7(); // 7 #NM 设备不可用(无数学协处理器) void isr8(); // 8 #DF 双重故障(有错误代码) void isr9(); // 9 协处理器跨段操作 void isr10(); // 10 #TS 无效TSS(有错误代码) void isr11(); // 11 #NP 段不存在(有错误代码) void isr12(); // 12 #SS 栈错误(有错误代码) void isr13(); // 13 #GP 常规保护(有错误代码) void isr14(); // 14 #PF 页故障(有错误代码) void isr15(); // 15 CPU 保留 void isr16(); // 16 #MF 浮点处理单元错误 void isr17(); // 17 #AC 对齐检查 void isr18(); // 18 #MC 机器检查 void isr19(); // 19 #XM SIMD(单指令多数据)浮点异常 // 20-31 Intel 保留 void isr20(); void isr21(); void isr22(); void isr23(); void isr24(); void isr25(); void isr26(); void isr27(); void isr28(); void isr29(); void isr30(); void isr31(); // 32~255 用户自定义异常 void isr128(); // IRQ 处理函数 void irq_handler(pt_regs_t *regs); // 定义IRQ #define IRQ0 32 // 电脑系统计时器 #define IRQ1 33 // 键盘 #define IRQ2 34 // 与 IRQ9 相接,MPU-401 MD 使用 #define IRQ3 35 // 串口设备 #define IRQ4 36 // 串口设备 #define IRQ5 37 // 建议声卡使用 #define IRQ6 38 // 软驱传输控制使用 #define IRQ7 39 // 打印机传输控制使用 #define IRQ8 40 // 即时时钟 #define IRQ9 41 // 与 IRQ2 相接,可设定给其他硬件 #define IRQ10 42 // 建议网卡使用 #define IRQ11 43 // 建议 AGP 显卡使用 #define IRQ12 44 // 接 PS/2 鼠标,也可设定给其他硬件 #define IRQ13 45 // 协处理器使用 #define IRQ14 46 // IDE0 传输控制使用 #define IRQ15 47 // IDE1 传输控制使用 // 声明 IRQ 函数 // IRQ:中断请求(Interrupt Request) void irq0(); // 电脑系统计时器 void irq1(); // 键盘 void irq2(); // 与 IRQ9 相接,MPU-401 MD 使用 void irq3(); // 串口设备 void irq4(); // 串口设备 void irq5(); // 建议声卡使用 void irq6(); // 软驱传输控制使用 void irq7(); // 打印机传输控制使用 void irq8(); // 即时时钟 void irq9(); // 与 IRQ2 相接,可设定给其他硬件 void irq10(); // 建议网卡使用 void irq11(); // 建议 AGP 显卡使用 void irq12(); // 接 PS/2 鼠标,也可设定给其他硬件 void irq13(); // 协处理器使用 void irq14(); // IDE0 传输控制使用 void irq15(); // IDE1 传输控制使用 // 初始化中断描述符表 void idt_init(void); #endif // IDT_H_ ================================================ FILE: arch/i386/intr/intr_s.s ================================================ ; -------------------------------------------------- ; 将 IDT 地址 载入 IDTR ; ; qianyi.lh 2014/11/04 14:44:23 ;--------------------------------------------------- [GLOBAL idt_flush] idt_flush: mov eax, [esp+4] ; 参数存入 eax 寄存器 lidt [eax] ; 加载到 IDTR ret .end: ; 定义两个构造中断处理函数的宏(有的中断有错误代码,有的没有) ; 用于没有错误代码的中断 %macro ISR_NOERRCODE 1 [GLOBAL isr%1] isr%1: push 0 ; push 无效的中断错误代码(起到占位作用,便于所有isr函数统一清栈) push %1 ; push 中断号 jmp isr_common_stub %endmacro ; 用于有错误代码的中断 %macro ISR_ERRCODE 1 [GLOBAL isr%1] isr%1: push %1 ; push 中断号 jmp isr_common_stub %endmacro ; 定义中断处理函数 ISR_NOERRCODE 0 ; 0 #DE 除 0 异常 ISR_NOERRCODE 1 ; 1 #DB 调试异常 ISR_NOERRCODE 2 ; 2 NMI ISR_NOERRCODE 3 ; 3 BP 断点异常 ISR_NOERRCODE 4 ; 4 #OF 溢出 ISR_NOERRCODE 5 ; 5 #BR 对数组的引用超出边界 ISR_NOERRCODE 6 ; 6 #UD 无效或未定义的操作码 ISR_NOERRCODE 7 ; 7 #NM 设备不可用(无数学协处理器) ISR_ERRCODE 8 ; 8 #DF 双重故障(有错误代码) ISR_NOERRCODE 9 ; 9 协处理器跨段操作 ISR_ERRCODE 10 ; 10 #TS 无效TSS(有错误代码) ISR_ERRCODE 11 ; 11 #NP 段不存在(有错误代码) ISR_ERRCODE 12 ; 12 #SS 栈错误(有错误代码) ISR_ERRCODE 13 ; 13 #GP 常规保护(有错误代码) ISR_ERRCODE 14 ; 14 #PF 页故障(有错误代码) ISR_NOERRCODE 15 ; 15 CPU 保留 ISR_NOERRCODE 16 ; 16 #MF 浮点处理单元错误 ISR_ERRCODE 17 ; 17 #AC 对齐检查 ISR_NOERRCODE 18 ; 18 #MC 机器检查 ISR_NOERRCODE 19 ; 19 #XM SIMD(单指令多数据)浮点异常 ; 20~31 Intel 保留 ISR_NOERRCODE 20 ISR_NOERRCODE 21 ISR_NOERRCODE 22 ISR_NOERRCODE 23 ISR_NOERRCODE 24 ISR_NOERRCODE 25 ISR_NOERRCODE 26 ISR_NOERRCODE 27 ISR_NOERRCODE 28 ISR_NOERRCODE 29 ISR_NOERRCODE 30 ISR_NOERRCODE 31 ; 32~255 用户自定义 ISR_NOERRCODE 128 ; 0x80 syscall [GLOBAL isr_common_stub] [EXTERN isr_handler] ; 中断服务程序 isr_common_stub: pusha ; Pushes edi, esi, ebp, esp, ebx, edx, ecx, eax mov ax, ds push eax ; 保存数据段描述符 mov ax, 0x10 ; 加载内核数据段描述符表 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax push esp ; 此时的 esp 寄存器的值等价于 pt_regs 结构体的指针 call isr_handler ; 在 C 语言代码里 add esp, 4 ; 清除压入的参数 pop ebx ; 恢复原来的数据段描述符 mov ds, bx mov es, bx mov fs, bx mov gs, bx mov ss, bx popa ; Pops edi, esi, ebp, esp, ebx, edx, ecx, eax add esp, 8 ; 清理栈里的 error code 和 ISR iret .end: ; 构造中断请求的宏 %macro IRQ 2 [GLOBAL irq%1] irq%1: push 0 push %2 jmp irq_common_stub %endmacro IRQ 0, 32 ; 电脑系统计时器 IRQ 1, 33 ; 键盘 IRQ 2, 34 ; 与 IRQ9 相接,MPU-401 MD 使用 IRQ 3, 35 ; 串口设备 IRQ 4, 36 ; 串口设备 IRQ 5, 37 ; 建议声卡使用 IRQ 6, 38 ; 软驱传输控制使用 IRQ 7, 39 ; 打印机传输控制使用 IRQ 8, 40 ; 即时时钟 IRQ 9, 41 ; 与 IRQ2 相接,可设定给其他硬件 IRQ 10, 42 ; 建议网卡使用 IRQ 11, 43 ; 建议 AGP 显卡使用 IRQ 12, 44 ; 接 PS/2 鼠标,也可设定给其他硬件 IRQ 13, 45 ; 协处理器使用 IRQ 14, 46 ; IDE0 传输控制使用 IRQ 15, 47 ; IDE1 传输控制使用 [GLOBAL irq_common_stub] [GLOBAL forkret_s] [EXTERN irq_handler] irq_common_stub: pusha ; pushes edi, esi, ebp, esp, ebx, edx, ecx, eax mov ax, ds push eax ; 保存数据段描述符 mov ax, 0x10 ; 加载内核数据段描述符 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax push esp call irq_handler add esp, 4 forkret_s: pop ebx ; 恢复原来的数据段描述符 mov ds, bx mov es, bx mov fs, bx mov gs, bx mov ss, bx popa ; Pops edi,esi,ebp... add esp, 8 ; 清理压栈的 错误代码 和 ISR 编号 iret ; 出栈 CS, EIP, EFLAGS, SS, ESP .end: ================================================ FILE: arch/i386/mm/fault.c ================================================ /* * ===================================================================================== * * Filename: fault.c * * Description: 页错误处理 * * Version: 1.0 * Created: 2014年11月05日 09时58分02秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include void do_page_fault(pt_regs_t *regs) { uint32_t cr2; __asm__ volatile ("mov %%cr2, %0" : "=r" (cr2)); printk("Page fault at EIP: 0x%x, virtual faulting address 0x%x\n", regs->eip, cr2); printk("Error code: %x\n", regs->err_code); // bit 0 为 0 指页面不存在内存里 if ( !(regs->err_code & 0x1)) { cprintk(rc_black, rc_red, "Because the page wasn't present.\n"); } // bit 1 为 0 表示读错误,为 1 为写错误 if (regs->err_code & 0x2) { cprintk(rc_black, rc_red, "Write error.\n"); } else { cprintk(rc_black, rc_red, "Read error.\n"); } // bit 2 为 1 表示在用户模式打断的,为 0 是在内核模式打断的 if (regs->err_code & 0x4) { cprintk(rc_black, rc_red, "In user mode.\n"); } else { cprintk(rc_black, rc_red, "In kernel mode.\n"); } // bit 3 为 1 表示错误是由保留位覆盖造成的 if (regs->err_code & 0x8) { cprintk(rc_black, rc_red, "Reserved bits being overwritten.\n"); } // bit 4 为 1 表示错误发生在取指令的时候 if (regs->err_code & 0x10) { cprintk(rc_black, rc_red, "The fault occurred during an instruction fetch.\n"); } while (1) { cpu_hlt(); } } ================================================ FILE: arch/i386/mm/gdt.c ================================================ /* * ===================================================================================== * * Filename: gdt.c * * Description: 全局描述符表相关 * * Version: 1.0 * Created: 2014年11月04日 14时13分14秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include "gdt.h" // 全局描述符类型 typedef struct gdt_entry_t { uint16_t limit_low; // 段界限 15~0 uint16_t base_low; // 段基地址 15~0 uint8_t base_middle; // 段基地址 23~16 uint8_t access; // 段存在位、描述符特权级、描述符类型、描述符子类别 uint8_t granularity; // 其他标志、段界限 19~16 uint8_t base_high; // 段基地址 31~24 } __attribute__((packed)) gdt_entry_t; // 全局描述符表定义 static gdt_entry_t gdt_entries[GDT_LENGTH] __attribute__ ((aligned(8))); static void gdt_set_gate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) { gdt_entries[num].base_low = (base & 0xFFFF); gdt_entries[num].base_middle = (base >> 16) & 0xFF; gdt_entries[num].base_high = (base >> 24) & 0xFF; gdt_entries[num].limit_low = (limit & 0xFFFF); gdt_entries[num].granularity = (limit >> 16) & 0x0F; gdt_entries[num].granularity |= gran & 0xF0; gdt_entries[num].access = access; } // TSS 段定义 static tss_entry_t tss_entry __attribute__ ((aligned(8))); static void tss_set_gate(int32_t num, uint16_t ss0, uint32_t esp0) { // 获取 TSS 描述符的位置和长度 uint32_t base = (uint32_t)&tss_entry; uint32_t limit = base + sizeof(tss_entry); // 在 GDT 表中增加 TSS 段描述 gdt_set_gate(num, base, limit, 0x89, 0x40); // 设置内核栈的地址 tss_entry.ts_ss0 = ss0; tss_entry.ts_esp0 = esp0; tss_entry.ts_cs = USER_CS; tss_entry.ts_ss = USER_DS; tss_entry.ts_ds = USER_DS; tss_entry.ts_es = USER_DS; tss_entry.ts_fs = USER_DS; tss_entry.ts_gs = USER_DS; } // GDTR typedef struct gdt_ptr_t { uint16_t limit; // 全局描述符表限长 uint32_t base; // 全局描述符表 32位 基地址 } __attribute__((packed)) gdt_ptr_t; // GDTR static gdt_ptr_t gdt_ptr; // 初始化全局描述符表 void gdt_init(void) { // 全局描述符表界限 从 0 开始,所以总长要 - 1 gdt_ptr.limit = sizeof(gdt_entry_t) * GDT_LENGTH - 1; gdt_ptr.base = (uint32_t)&gdt_entries; // 采用 Intel 平坦模型 gdt_set_gate(SEG_NULL, 0x0, 0x0, 0x0, 0x0); // Intel文档要求首个描述符全0 gdt_set_gate(SEG_KTEXT, 0x0, 0xFFFFFFFF, 0x9A, 0xC0); // 内核指令段 gdt_set_gate(SEG_KDATA, 0x0, 0xFFFFFFFF, 0x92, 0xC0); // 内核数据段 gdt_set_gate(SEG_UTEXT, 0x0, 0xFFFFFFFF, 0xFA, 0xC0); // 用户模式代码段 gdt_set_gate(SEG_UDATA, 0x0, 0xFFFFFFFF, 0xF2, 0xC0); // 用户模式数据段 tss_set_gate(SEG_TSS, KERNEL_DS, 0); // 加载全局描述符表地址到 GPTR 寄存器 gdt_flush((uint32_t)&gdt_ptr); // 加载任务寄存器 tss_flush(); } ================================================ FILE: arch/i386/mm/gdt.h ================================================ /* * ===================================================================================== * * Filename: gdt.h * * Description: 全局描述符表支持 * * Version: 1.0 * Created: 2014年11月04日 14时11分51秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef GDT_H_ #define GDT_H_ #include // 全局描述符表长度 #define GDT_LENGTH 6 // 各个内存段所在全局描述符表下标 #define SEG_NULL 0 #define SEG_KTEXT 1 #define SEG_KDATA 2 #define SEG_UTEXT 3 #define SEG_UDATA 4 #define SEG_TSS 5 #define GD_KTEXT ((SEG_KTEXT) << 3) // 内核代码段 #define GD_KDATA ((SEG_KDATA) << 3) // 内核数据段 #define GD_UTEXT ((SEG_UTEXT) << 3) // 用户代码段 #define GD_UDATA ((SEG_UDATA) << 3) // 用户数据段 #define GD_TSS ((SEG_TSS) << 3) // 任务段 // 段描述符 DPL #define DPL_KERNEL (0) #define DPL_USER (3) // 各个段的全局描述符表的选择子 #define KERNEL_CS ((GD_KTEXT) | DPL_KERNEL) #define KERNEL_DS ((GD_KDATA) | DPL_KERNEL) #define USER_CS ((GD_UTEXT) | DPL_USER) #define USER_DS ((GD_UDATA) | DPL_USER) // TSS 描述符 typedef struct tss_entry_t { uint32_t ts_link; // old ts selector uint32_t ts_esp0; // stack pointers and segment selectors uint16_t ts_ss0; // after an increase in privilege level uint16_t ts_padding1; uint32_t ts_esp1; uint16_t ts_ss1; uint16_t ts_padding2; uint32_t ts_esp2; uint16_t ts_ss2; uint16_t ts_padding3; uint32_t ts_cr3; // page directory base uint32_t ts_eip; // saved state from last task switch uint32_t ts_eflags; uint32_t ts_eax; // more saved state (registers) uint32_t ts_ecx; uint32_t ts_edx; uint32_t ts_ebx; uint32_t ts_esp; uint32_t ts_ebp; uint32_t ts_esi; uint32_t ts_edi; uint16_t ts_es; // even more saved state (segment selectors) uint16_t ts_padding4; uint16_t ts_cs; uint16_t ts_padding5; uint16_t ts_ss; uint16_t ts_padding6; uint16_t ts_ds; uint16_t ts_padding7; uint16_t ts_fs; uint16_t ts_padding8; uint16_t ts_gs; uint16_t ts_padding9; uint16_t ts_ldt; uint16_t ts_padding10; uint16_t ts_t; // trap on task switch uint16_t ts_iomb; // i/o map base address } __attribute__((packed)) tss_entry_t; // 初始化全局描述符表 void gdt_init(void); // GDT 加载到 GDTR 的函数 extern void gdt_flush(); // TSS 刷新[汇编实现] extern void tss_flush(); #endif // GDT_H_ ================================================ FILE: arch/i386/mm/gdt_s.s ================================================ ; ------------------------------------------------- ; GDTR 和 TR 相关操作 ; ; qianyi.lh 2014/11/04 14:15:54 ; ------------------------------------------------- [GLOBAL gdt_flush] gdt_flush: mov eax, [esp+4] ; 参数存入 eax 寄存器 lgdt [eax] ; 加载到 GDTR [修改原先GRUB设置] mov ax, 0x10 ; 加载数据段描述符 mov ds, ax ; 更新所有可以更新的段寄存器 mov es, ax mov fs, ax mov gs, ax mov ss, ax jmp 0x08:.flush ; 远跳转,0x08是代码段描述符 ; 远跳目的是清空流水线并串行化处理器 .flush: ret [GLOBAL tss_flush] ; TSS 刷新 tss_flush: mov ax, 0x28 ; TSS 在全局描述符表里是第5个 ; 故而 00101000B 即就是 0x28 ltr ax ; 加载到 TR 寄存器 ret ================================================ FILE: arch/i386/mm/pmm.c ================================================ /* * ===================================================================================== * * Filename: pmm.c * * Description: 物理内存管理 * * Version: 1.0 * Created: 2014年11月04日 13时13分04秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #include #include #include #include // 物理内存管理算法 static const struct pmm_manager *pmm_manager = &ff_mm_manager; // 物理页帧数组指针 (内核结束地址[实地址]+内核基址+内核页表保留地址) static page_t *phy_pages = (page_t *)((uint32_t)kern_end + KERNBASE + KVPAGE_SIZE); // 物理页帧数组长度 static uint32_t phy_pages_count; // 可用物理内存页起始地址 static uint32_t pmm_addr_start; // 可用物理内存页结束地址 static uint32_t pmm_addr_end; // 获取可用内存的起始和结束地址 static void get_ram_info(e820map_t *e820map); // 物理内存页初始化 static void phy_pages_init(e820map_t *e820map); void pmm_init(void) { show_kernel_memory_map(); e820map_t e820map; bzero(&e820map, sizeof(e820map)); get_ram_info(&e820map); phy_pages_init(&e820map); page_init(phy_pages, phy_pages_count); } static void get_ram_info(e820map_t *e820map) { mmap_entry_t *mmap_start_addr = (mmap_entry_t *)glb_mboot_ptr->mmap_addr; mmap_entry_t *mmap_end_addr = (mmap_entry_t *)glb_mboot_ptr->mmap_addr + glb_mboot_ptr->mmap_length; mmap_entry_t *map_entry; for (map_entry = mmap_start_addr; map_entry < mmap_end_addr; map_entry++) { if (map_entry->type == MULTIBOOT_TYPE_RAM && map_entry->base_addr_low == RAM_KERNEL_START) { e820map->map[e820map->count].addr_low = map_entry->base_addr_low; e820map->map[e820map->count].addr_high = map_entry->base_addr_high; e820map->map[e820map->count].length_low = map_entry->length_low; e820map->map[e820map->count].length_high = map_entry->length_high; e820map->map[e820map->count].type = E820_ARM; e820map->count++; } } } static void phy_pages_init(e820map_t *e820map) { uint32_t phy_mem_length = 0; for (uint32_t i = 0; i < e820map->count; ++i){ if (e820map->map[i].addr_low > ZONE_HIGHMEM_ADDR) { break; } if (e820map->map[i].addr_low + e820map->map[i].length_low > ZONE_HIGHMEM_ADDR) { phy_mem_length = ZONE_HIGHMEM_ADDR; break; } phy_mem_length += e820map->map[i].length_low; } uint32_t pages_mem_length = sizeof(page_t) * (phy_mem_length / PMM_PAGE_SIZE); bzero(phy_pages, pages_mem_length); // 物理内存页管理起始地址 pmm_addr_start = ((uint32_t)phy_pages - KERNBASE + pages_mem_length + PMM_PAGE_SIZE) & PMM_PAGE_MASK; for (uint32_t i = 0; i < e820map->count; ++i){ uint32_t start_addr = e820map->map[i].addr_low; uint32_t end_addr = e820map->map[i].addr_low + e820map->map[i].length_low; if (start_addr < pmm_addr_start) { start_addr = pmm_addr_start; } if (end_addr > ZONE_HIGHMEM_ADDR) { end_addr = ZONE_HIGHMEM_ADDR; } for (uint32_t addr = start_addr; addr < end_addr; addr += PMM_PAGE_SIZE) { phy_pages_count++; } pmm_addr_end = end_addr; } assert(pmm_addr_start == page_to_addr(&phy_pages[0]), "phy_pages_init error pmm_start != &page[0]"); assert(pmm_addr_end - PMM_PAGE_SIZE == page_to_addr(&phy_pages[phy_pages_count-1]), "phy_pages_init error pmm_end != &page[n-1]"); assert(&phy_pages[0] == addr_to_page(page_to_addr(&phy_pages[0])), "phy_pages_init error addr_to_page error"); assert(&phy_pages[1] == addr_to_page(page_to_addr(&phy_pages[1])), "phy_pages_init error addr_to_page error"); } page_t *addr_to_page(uint32_t addr) { assert(pmm_addr_start != 0, "memory not init, addr_to_page cannot use"); return (phy_pages + ((addr & PMM_PAGE_MASK) - pmm_addr_start) / PMM_PAGE_SIZE); } uint32_t page_to_addr(page_t *page) { assert(pmm_addr_start != 0, "memory not init, addr_to_page cannot use"); return (pmm_addr_start + (uint32_t)(page - phy_pages) * PMM_PAGE_SIZE); } void page_init(page_t *pages, uint32_t n) { pmm_manager->page_init(pages, n); } uint32_t alloc_pages(uint32_t n) { uint32_t page; uint32_t eflag; local_intr_store(eflag); page = pmm_manager->alloc_pages(n); local_intr_restore(eflag); return page; } void free_pages(uint32_t addr, uint32_t n) { uint32_t eflag; local_intr_store(eflag); pmm_manager->free_pages(addr, n); local_intr_restore(eflag); } uint32_t free_pages_count(void) { return pmm_manager->free_pages_count(); } ================================================ FILE: arch/i386/mm/pmm.h ================================================ /* * ===================================================================================== * * Filename: pmm.h * * Description: 物理内存管理 * * Version: 1.0 * Created: 2014年11月04日 13时03分24秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_MM_PMM_H #define INCLUDE_MM_PMM_H #include #include // 默认栈的大小(4096) #define STACK_SIZE (0x1000) // 物理内存页框大小 #define PMM_PAGE_SIZE (0x1000) // 页掩码 按照 0x1000(4096) 对齐地址 #define PMM_PAGE_MASK (0xFFFFF000) // 内核在物理内存起始位置 #define RAM_KERNEL_START (0x100000) // 内核代码在内存中的起始和结束位置,在链接脚本中定义 extern uint8_t kern_start[]; extern uint8_t kern_end[]; // 开启分页机制之后的内核栈 extern uint8_t kern_stack[STACK_SIZE]; // 内核栈的栈顶 extern uint32_t kern_stack_top; // BIOS int 0x15 AX = 0xE820 常量 #define E820MAX (20) // 最大的表项数目 #define E820_ARM (1) // 可用 RAM #define E820_ARR (2) // 保留区域 typedef struct e820map_t { uint32_t count; struct { uint32_t addr_low; uint32_t addr_high; uint32_t length_low; uint32_t length_high; uint32_t type; } __attribute__((packed)) map[E820MAX]; } e820map_t; // 内存页类型 typedef enum mem_zone_t { ZONE_DMA = 0, ZONE_NORMAL = 1, ZONE_HIGHMEM = 2 } mem_zone_t; #define ZONE_NORMAL_ADDR (0x1000000) // 16 MB #define ZONE_HIGHMEM_ADDR (0x38000000) // 896 MB // 物理页结构 typedef struct page_t { atomic_t ref; // 物理页被引用的次数 uint32_t flag; // 当前页状态 union { uint32_t ncount; // 当前页后续连续页的数量 First-Fit算法需要 uint32_t order; // 当前页的 order 值 buddy 算法需要 }; struct list_head list; // 链接下一个连续页 } page_t; // page_t 的 flag 参数的操作宏 #define PG_RESERVED (0) // 1 << 0 表示页当前不可用 #define PG_NCOUNT (1) // 1 << 1 表示 ncount 字段有效 #define PG_ORDER (2) // 1 << 2 表示 order 字段有效 #define set_page_reserved_flag(page) set_bit(PG_RESERVED, &((page)->flag)) #define clear_page_reserved_flag(page) clear_bit(PG_RESERVED, &((page)->flag)) #define is_page_reserved(page) test_bit(PG_RESERVED, &((page)->flag)) #define set_page_ncount_flag(page) set_bit(PG_NCOUNT, &((page)->flag)) #define clear_page_ncount_flag(page) clear_bit(PG_NCOUNT, &((page)->flag)) #define is_page_ncount(page) test_bit(PG_NCOUNT, &((page)->flag)) #define set_page_order_flag(page) set_bit(PG_ORDER, &((page)->flag)) #define clear_page_order_flag(page) clear_bit(PG_ORDER, &((page)->flag)) #define is_page_order(page) test_bit(PG_ORDER, &((page)->flag)) static inline int32_t page_ref(page_t *page) { return atomic_read(&page->ref); } static inline void set_page_ref(page_t *page, int32_t val) { atomic_set(&page->ref, val); } static inline void page_ref_inc(page_t *page) { atomic_inc(&page->ref); } static inline void page_ref_dec(page_t *page) { atomic_dec(&page->ref); } // 由物理地址计算出该地址所处页的管理结构的指针 page_t *addr_to_page(uint32_t addr); // 由页的管理结构的指针计算出页所在物理地址 uint32_t page_to_addr(page_t *page); // 内存管理子系统管理对象 struct pmm_manager { const char *name; // 管理算法的名称 void (*page_init)(page_t *pages, uint32_t n); // 初始化 uint32_t (*alloc_pages)(uint32_t n); // 申请物理内存页(n为字节数) void (*free_pages)(uint32_t addr, uint32_t n); // 释放内存页 uint32_t (*free_pages_count)(void); // 返回当前可用内存页 }; // 物理内存管理初始化 void pmm_init(void); // 内存管理算法初始化 void page_init(page_t *pages, uint32_t n); // 申请内存页 uint32_t alloc_pages(uint32_t n); // 释放内存页 void free_pages(uint32_t addr, uint32_t n); #define alloc_page alloc_pages(1) #define free_page(addr) free_pages(addr, 1) // 当前可用内存页 uint32_t free_pages_count(void); #endif // INCLUDE_MM_PMM_H ================================================ FILE: arch/i386/mm/vmm.c ================================================ /* * ===================================================================================== * * Filename: vmm.c * * Description: 虚拟内存管理 * * Version: 1.0 * Created: 2014年11月05日 09时55分49秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #include // 内核页目录 pgd_t pgd_kern[PGD_SIZE] __attribute__ ((aligned(PAGE_SIZE))); // 内核页表起始 static pte_t *pte_addr = (pte_t *)((uint32_t)kern_end + KERNBASE); void vmm_init(void) { // 注册页错误中断的处理函数 register_interrupt_handler(INT_PAGE_FAULT, &do_page_fault); // 页表数组指针 pte_t (*pte_kern)[PTE_SIZE] = (pte_t (*)[PTE_SIZE])pte_addr; // 构造页目录(MMU需要的是物理地址,此处需要减去偏移) uint32_t pgd_idx = PGD_INDEX(PAGE_OFFSET); for (uint32_t i = pgd_idx; i < pgd_idx + PTE_COUNT; ++i) { pgd_kern[i] = ((uint32_t)ka_to_pa(pte_kern[i])) | PAGE_PRESENT | PAGE_WRITE; } // 构造页表映射,内核 0xC0000000~0xF8000000 映射到 物理 0x00000000~0x38000000 (物理内存前896MB) uint32_t *pte_start = (uint32_t *)(pte_addr + PTE_SIZE * pgd_idx); for (uint32_t i = 0; i < PTE_SIZE * PTE_COUNT; ++i) { pte_start[i] = (i << 12) | PAGE_PRESENT | PAGE_WRITE; } switch_pgd((uint32_t)ka_to_pa(pgd_kern)); } void map(pgd_t *pgd_now, uint32_t va, uint32_t pa, uint32_t flags) { uint32_t pgd_idx = PGD_INDEX(va); uint32_t pte_idx = PTE_INDEX(va); pte_t *pte = (pte_t *)(pgd_now[pgd_idx] & PAGE_MASK); if (!pte) { pte = (pte_t *)alloc_pages(1); pgd_now[pgd_idx] = (uint32_t)pte | PAGE_PRESENT | PAGE_WRITE; pte = (pte_t *)pa_to_ka(pte); } else { pte = (pte_t *)pa_to_ka(pte); } pte[pte_idx] = (pa & PAGE_MASK) | flags; tlb_reload_page(va); } void unmap(pgd_t *pgd_now, uint32_t va) { uint32_t pgd_idx = PGD_INDEX(va); uint32_t pte_idx = PTE_INDEX(va); pte_t *pte = (pte_t *)(pgd_now[pgd_idx] & PAGE_MASK); if (!pte) { return; } // 转换到内核线性地址 pte = (pte_t *)(pa_to_ka(pte)); pte[pte_idx] = 0; tlb_reload_page(va); } uint32_t get_mapping(pgd_t *pgd_now, uint32_t va, uint32_t *pa) { uint32_t pgd_idx = PGD_INDEX(va); uint32_t pte_idx = PTE_INDEX(va); pte_t *pte = (pte_t *)(pgd_now[pgd_idx] & PAGE_MASK); if (!pte) { return 0; } // 转换到内核线性地址 pte = (pte_t *)(pa_to_ka(pte)); // 如果地址有效而且指针不为NULL,则返回地址 if (pte[pte_idx] != 0 && pa) { *pa = pte[pte_idx] & PAGE_MASK; return 1; } return 0; } ================================================ FILE: arch/i386/mm/vmm.h ================================================ /* * ===================================================================================== * * Filename: vmm.h * * Description: 虚拟内存管理相关 * * Version: 1.0 * Created: 2014年11月04日 11时41分59秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_MM_VMM_H #define INCLUDE_MM_VMM_H #include #include #include /* * * Virtual memory map: * * * 4G ------------------> +---------------------------------+ * | | * | Empty Memory (*) | * | | * +---------------------------------+ 0xF8000000 * | | * | | * | Remapped Physical Memory | RW/-- KMEMSIZE * | | * | | * +---------------------------------+ * | Kernel | * KERNBASE ------------> +---------------------------------+ 0xC0000000 * | Invalid Memory (*) | --/-- * USERTOP -------------> +---------------------------------+ 0xB0000000 * | User stack | * +---------------------------------+ * : : * | ~~~~~~~~~~~~~~~~ | * : : * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * | User Program & Heap | * UTEXT ---------------> +---------------------------------+ 0x00800000 * | Invalid Memory (*) | --/-- * USERBASE -----------> +---------------------------------+ 0x00200000 * | Invalid Memory (*) | --/-- * 0 -------------------> +---------------------------------+ 0x00000000 * (*) Note: The kernel ensures that "Invalid Memory" is *never* mapped. * "Empty Memory" is normally unmapped, but user programs may map pages * there if desired. * * */ // A linear address 'la' has a three-part structure as follows: // // +--------10------+-------10-------+---------12----------+ // | Page Directory | Page Table | Offset within Page | // | Index | Index | | // +----------------+----------------+---------------------+ // \PGD_INDEX(la)/ \ PTE_INDEX(la) / \OFFSET_INDEX(la)/ // 虚拟分页大小(4KB) #define PAGE_SIZE (0x1000) // 页掩码,用于 4KB 对齐 #define PAGE_MASK (0xFFFFF000) // 内核起始虚拟地址 #define KERNBASE (0xC0000000) // 内核管理内存的大小 #define KMEMSIZE (0x38000000) // 内核页表大小 #define KVPAGE_SIZE (0x400000) // 内核管理的物理内存的顶端地址 #define KERNTOP (KERNBASE + KMEMSIZE) // 内核的偏移地址 #define PAGE_OFFSET KERNBASE // 每个页表可以映射的内存数 #define PAGE_MAP_SIZE (0x400000) // 映射 KMEM_SIZE 的内存所需要的页数 #define PTE_COUNT (KMEMSIZE/PAGE_MAP_SIZE) // 获取一个地址的页目录项 #define PGD_INDEX(x) (((x) >> 22) & 0x3FF) // 获取一个地址的页表项 #define PTE_INDEX(x) (((x) >> 12) & 0x3FF) // 获取一个地址的页內偏移 #define OFFSET_INDEX(x) ((x) & 0xFFF) // P--位0是存在标识,为 1 则内存页在内存中 #define PAGE_PRESENT (0x1) // R/W--位1是读/写标识,如果等于 1,表示页面可以被读、写或执行。 #define PAGE_WRITE (0x2) // U/S--位2是用户/超级用户标识,为 1 则任何特权级上的程序都可以访问该页面。 #define PAGE_USER (0x4) // 页表成员数 #define PGD_SIZE (PAGE_SIZE/sizeof(pte_t)) // 页表成员数 #define PTE_SIZE (PAGE_SIZE/sizeof(uint32_t)) // 任务内存信息 struct mm_struct { pgd_t *pgdir; int vma_count; struct list_head vma_list; }; // 任务虚拟内存区间 struct vma_struct { struct mm_struct *mm; uint32_t vm_start; uint32_t vm_end; uint32_t vm_flags; struct list_head list; }; #define le_to_vma(le) list_entry(le, struct vma_struct, list) #define VM_READ (1u << 0) #define VM_WRITE (1u << 1) #define VM_EXEC (1u << 2) // 物理地址转换内核虚拟地址 static inline void *pa_to_ka(void *pa) { return (void *)((uint32_t)pa + KERNBASE); } // 内核虚拟地址转换物理地址 static inline void *ka_to_pa(void *ka) { return (void *)((uint32_t)ka - KERNBASE); } // 内核页目录区域 extern pgd_t pgd_kern[]; // 虚拟内存管理初始化 void vmm_init(void); // 使用 flags 指出的页权限,把物理地址 pa 映射到虚拟地址 va void map(pgd_t *pgd_now, uint32_t va, uint32_t pa, uint32_t flags); // 取消虚拟地址 va 的物理映射 void unmap(pgd_t *pgd_now, uint32_t va); // 如果虚拟地址 va 映射到物理地址则返回 1 // 同时如果 pa 不是空指针则把物理地址写入 pa 参数 uint32_t get_mapping(pgd_t *pgd_now, uint32_t va, uint32_t *pa); // 页错误中断的函数处理 void do_page_fault(pt_regs_t *regs); #endif // INCLUDE_MM_VMM_H ================================================ FILE: arch/i386/syscall/syscall.c ================================================ /* * ===================================================================================== * * Filename: syscall.c * * Description: 系统调用相关 * * Version: 1.0 * Created: 2014年11月16日 12时19分36秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #include "syscall.h" static int sys_test(uint32_t args[]) { int errno = (int)args[0]; cprintk(rc_black, rc_light_brown, "\n\tsys_test run here!\n"); return errno; } static int sys_exit(uint32_t args[]) { int errno = (int)args[0]; return errno; } static int sys_fork(uint32_t args[]) { int errno = (int)args[0]; return errno; } static int sys_read(uint32_t args[]) { int fd = (int)args[0]; char *buff = (char *)args[1]; size_t size = (size_t)args[2]; return vfs_read(fd, buff, size);; } static int sys_write(uint32_t args[]) { int fd = (int)args[0]; const char *buff = (const char *)args[1]; size_t size = (size_t)args[2]; return vfs_write(fd, buff, size); } static int sys_open(uint32_t args[]) { const char *filename = (const char *)args[0]; uint32_t openflag = args[1]; return vfs_open(filename, openflag); } static int sys_close(uint32_t args[]) { int fd = (int)args[0]; return vfs_close(fd); } static int sys_getpid(uint32_t args[]) { int errno = (int)args[0]; return errno; } // 系统调用函数指针数组 static int (*syscalls[])(uint32_t args[]) = { [SYS_test] = sys_test, [SYS_exit] = sys_exit, [SYS_fork] = sys_fork, [SYS_read] = sys_read, [SYS_write] = sys_write, [SYS_open] = sys_open, [SYS_close] = sys_close, [SYS_getpid] = sys_getpid }; void syscall_handler(pt_regs_t *regs) { uint32_t args[5]; int sysno = regs->eax; if (sysno >= 0 && sysno <= SYSCALL_MAX) { if (syscalls[sysno]) { // 系统调用寄存器传参规范 args[0] = regs->ebx; args[1] = regs->ecx; args[2] = regs->edx; args[3] = regs->esi; args[4] = regs->edi; // 返回值由 eax 寄存器带回 regs->eax = syscalls[sysno](args); } } } ================================================ FILE: arch/i386/syscall/syscall.h ================================================ /* * ===================================================================================== * * Filename: syscall.h * * Description: 系统调用相关 * * Version: 1.0 * Created: 2014年11月16日 12时17分43秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_SYSCALL_SYSCALL_H_ #define INCLUDE_SYSCALL_SYSCALL_H_ // 系统调用号 #define SYS_test 0 #define SYS_exit 1 #define SYS_fork 2 #define SYS_read 3 #define SYS_write 4 #define SYS_open 5 #define SYS_close 6 #define SYS_getpid 7 #define SYSCALL_MAX 7 // 系统调用函数 void syscall_handler(pt_regs_t *regs); #endif // INCLUDE_SYSCALL_SYSCALL_H_ ================================================ FILE: arch/i386/task/entry.s ================================================ ; ------------------------------------------------- ; 内核创建线程的统一入口函数 ; ; qianyi.lh 2014/11/12 14:45:54 ; ------------------------------------------------- [GLOBAL kthread_entry] [EXTERN do_exit] kthread_entry: push edx ; push args call ebx ; call fn push eax ; push fn(args) return code call do_exit ================================================ FILE: arch/i386/task/switch_to.s ================================================ ; ------------------------------------------------- ; 任务切换的实现 ; ; qianyi.lh 2014/11/12 16:38:56 ; ; ------------------------------------------------- [global switch_to] switch_to: mov eax, [esp+4] push ebx mov ebx, [esp+4] mov [eax], ebx pop ebx mov [eax+4], esp mov [eax+8], ebp mov [eax+12], ecx mov [eax+16], edx mov [eax+20], esi mov [eax+24], edi mov [eax+28], ebp mov eax, [esp+8] mov ebp, [eax+28] mov edi, [eax+24] mov esi, [eax+20] mov edx, [eax+16] mov ecx, [eax+12] mov ebx, [eax+8] mov esp, [eax+4] push ebx push ebx mov ebx, [eax] mov [esp+4], ebx pop ebx ret ================================================ FILE: arch/i386/task/task.c ================================================ /* * ===================================================================================== * * Filename: task.c * * Description: 任务相关的定义 * * Version: 1.0 * Created: 2014年11月12日 12时24分42秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #include #include #include #include "task.h" struct list_head task_list; struct task_struct *glb_idle_task; struct task_struct *glb_init_task; // 任务总数 static int nr_task = 0; static uint32_t glb_pid_map[MAX_PID/32]; static pid_t alloc_pid(void) { for (int i = 0; i < MAX_PID/32; ++i) { if (glb_pid_map[i] == 0xFFFFFFFF) { continue; } for (int j = 0; j < 32; ++j) { if (((1u << j) & glb_pid_map[i]) == 0) { glb_pid_map[i] |= 1u << j; return (pid_t)(i * 32 + j); } } } return -1; } static void free_pid(pid_t pid) { if (pid < 0 || pid > MAX_PID) { return; } glb_pid_map[pid/32] &= ~(1u << (pid % 32)); } void task_init(void) { INIT_LIST_HEAD(&task_list); struct task_struct *idle_task = (struct task_struct *)kern_stack; bzero(idle_task, sizeof(struct task_struct)); idle_task->state = TASK_RUNNABLE; idle_task->stack = (void *)kern_stack_top; idle_task->pid = alloc_pid(); idle_task->need_resched = true; set_proc_name(idle_task, "idle"); nr_task++; list_add(&idle_task->list, &task_list); glb_idle_task = idle_task; // 注册系统调用中断 register_interrupt_handler(0x80, syscall_handler); } // 声明创建的内核线程入口函数 extern int kthread_entry(void *args); int kernel_thread(int (*func)(void *), void *args, uint32_t clone_flags) { pt_regs_t pt_regs; bzero(&pt_regs, sizeof(pt_regs_t)); pt_regs.cs = KERNEL_CS; pt_regs.ds = KERNEL_DS; pt_regs.ss = KERNEL_DS; pt_regs.ebx = (uint32_t)func; pt_regs.edx = (uint32_t)args; pt_regs.eip = (uint32_t)kthread_entry; return do_fork(clone_flags | CLONE_VM, &pt_regs); } // 切换函数 extern void switch_to(struct context *from, struct context *to); void task_run(struct task_struct *task) { if (task != current) { struct task_struct *prev = current; struct task_struct *next = task; bool intr_flag = false; local_intr_store(intr_flag); { //tss_load_esp(uint32_t)next->stack); if (!task && task->mm && task->mm->pgdir) { // load cr3 } switch_to(&prev->context, &next->context); } local_intr_restore(intr_flag); } } struct task_struct *get_current(void) { register uint32_t esp __asm__ ("esp");; return (struct task_struct *)(esp & (~(STACK_SIZE-1))); } struct task_struct *find_task(pid_t pid) { if (pid > 0 && pid < MAX_PID) { struct list_head *le; list_for_each(le, &task_list) { struct task_struct *task = le_to_task(le); if (task->pid == pid) { return task; } } } return NULL; } void set_proc_name(struct task_struct *task, char *name) { bzero(task->name, sizeof(task->name)); strncpy(task->name, name, TASK_NAME_MAX); } static struct task_struct *alloc_task_struct(void) { void *addr = (void *)alloc_pages(STACK_SIZE/PAGE_SIZE); assert(addr != 0, "alloc_task_struct error!"); struct task_struct *task = pa_to_ka(addr); bzero(task, sizeof(struct task_struct)); task->state = TASK_UNINIT; task->stack = task_to_stack(task); task->pid = -1; return task; } static int copy_mm(uint32_t clone_flags, struct task_struct *task) { if (!clone_flags && !task) { return -1; } return 0; } // 定义在 intr_s.s void forkret_s(struct pt_regs_t *pt_regs); static void copy_thread(struct task_struct *task, struct pt_regs_t *pt_regs) { task->pt_regs = (struct pt_regs_t *)((uint32_t)task->stack - sizeof(struct pt_regs_t)); *(task->pt_regs) = *pt_regs; task->pt_regs->eax = 0; task->pt_regs->esp = (uint32_t)task->stack; task->pt_regs->eflags |= FL_IF; task->context.eip = (uint32_t)forkret_s; task->context.esp = (uint32_t)task->pt_regs; } pid_t do_fork(uint32_t clone_flags, struct pt_regs_t *pt_regs) { if (nr_task >= MAX_TASK) { return -E_NO_FREE_PROC; } struct task_struct *task = alloc_task_struct(); if (!task) { return -E_NO_MEM; } if (copy_mm(clone_flags, task) != 0) { free_pages((uint32_t)ka_to_pa(task), STACK_SIZE/PAGE_SIZE); return -E_NO_MEM; } copy_thread(task, pt_regs); bool intr_flag = false; local_intr_store(intr_flag); { task->pid = alloc_pid(); list_add(&task->list, &task_list); nr_task ++; } local_intr_restore(intr_flag); wakeup_task(task); return task->pid; } void do_exit(int errno) { bool intr_flag = false; local_intr_store(intr_flag); { current->state = TASK_ZOMBIE; current->exit_code = errno; current->need_resched = true; nr_task--; free_pid(current->pid); } local_intr_restore(intr_flag); cpu_idle(); } void cpu_idle(void) { if (current->need_resched) { schedule(); } } ================================================ FILE: arch/i386/task/task.h ================================================ /* * ===================================================================================== * * Filename: task.h * * Description: 任务相关定义 * * Version: 1.0 * Created: 2014年11月12日 10时18分52秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_TASK_H_ #define INCLUDE_TASK_H_ #include #include #include #include #include #include // fork flag #define CLONE_VM 0x00000100 // set if VM shared between processes #define CLONE_THREAD 0x00000200 // thread group // 任务状态字段 typedef enum task_state { TASK_UNINIT = 0, // 任务未初始化 TASK_SLEEPING = 1, // 任务休眠中 TASK_RUNNABLE = 2, // 任务可执行(可能正在执行) TASK_ZOMBIE = 3, // 任务已结束(等待回收) } task_state_t; // 按照 x86 规范保存被调用者需要保存的寄存器即可 struct context { uint32_t eip; uint32_t esp; uint32_t ebx; uint32_t ecx; uint32_t edx; uint32_t esi; uint32_t edi; uint32_t ebp; }; #define TASK_NAME_MAX (20) #define MAX_TASK (4096) #define MAX_PID (MAX_TASK*2) // 任务描述 PCB struct task_struct { task_state_t state; // 任务状态 void *stack; // 任务的内核栈指针 pid_t pid; // 任务的PID char name[TASK_NAME_MAX+1]; // 任务名称 uint32_t runs_time; // 当前任务运行时间 volatile bool need_resched; // 是否需要被重新调度 struct task_struct *parent; // 父进程指针 struct mm_struct *mm; // 任务的内存信息 struct pt_regs_t *pt_regs; // 任务中断保存的寄存器信息 struct context context; // 任务切换上下文信息 uint32_t flags; // 任务的一些标识 uint32_t exit_code; // 任务的退出代码 struct file_struct files; // 文件系统相关信息 struct list_head list; // 任务链表 }; #define le_to_task(le) list_entry(le, struct task_struct, list) extern struct list_head task_list; // idle 任务指针 extern struct task_struct *glb_idle_task; // init 任务指针 extern struct task_struct *glb_init_task; /* * 因为pt_regs结构最后的部分实际上是CPU自动压栈,内核访问的。 * 即中断产生后,CPU会自动压入这些寄存器,ss和sp仅在特权级发生变化时压入 * (比如从用户态ring0到ring3,会压入用户态的ss和sp), * 如果是内核态发生中断,CPU不会压入ss和sp,这种情况,再访问ss和sp字段就越界了, * 所以预留了8字节。 */ #define task_to_stack(task) ((void *)((uint32_t)task + STACK_SIZE - 8)) #define current get_current() // 获得当前执行的任务指针 struct task_struct *get_current(void); // 任务调度初始化 void task_init(void); // 运行一个任务 void task_run(struct task_struct *task); // 创建一个内核线程 int kernel_thread(int (*func)(void *), void *args, uint32_t clone_flags); // 通过 PID 查找任务 struct task_struct *find_task(pid_t pid); // 设置任务名称 void set_proc_name(struct task_struct *task, char *name); void cpu_idle(void); pid_t do_fork(uint32_t clone_flags, struct pt_regs_t *pt_regs); void do_exit(int errno); #endif // INCLUDE_TASK_H_ ================================================ FILE: arch/x64/TODO ================================================ TODO ================================================ FILE: driver/block_dev.c ================================================ /* * ===================================================================================== * * Filename: block_dev.c * * Description: 块设备相关 * * Version: 1.0 * Created: 2015年02月08日 10时12分00秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include // 全局块设备链表 block_dev_t *block_devs; // 块设备初始化 void block_dev_init(void) { cprintk(rc_black, rc_red, "Init IDE Driver ...\n"); block_dev_t *ide_dev = &ide_main_dev; if (ide_dev->ops.init() == -1) { printk("Main IDE Device Not Found!\n"); return; } add_block_dev(ide_dev); if (!ide_dev->ops.device_valid()) { printk("Main IDE Device Error!\n"); return; } cprintk(rc_black, rc_red, "Found IDE Driver: %u (sectors) Desc: %s\n", ide_dev->ops.get_nr_block(), ide_dev->ops.get_desc()); if (read_mbr_info(ide_dev) != 0) { printk("Read MBR Info Error!"); } } // 内核注册块设备 int add_block_dev(block_dev_t *bdev) { block_dev_t *p = block_devs; while (p) { if (strcmp(p->name, bdev->name) == 0) { return -1; } p = p->next; } bdev->next = block_devs; block_devs = bdev; return 0; } ================================================ FILE: driver/char_dev.c ================================================ /* * ===================================================================================== * * Filename: char_dev.c * * Description: 字符设备相关 * * Version: 1.0 * Created: 2015年02月08日 10时13分36秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include // 全局字符设备链表 char_dev_t *char_devs; // 字符设备初始化 void char_dev_init(void) { char_dev_t *kb_dev = &kboard_dev; kb_dev->ops.init(); add_char_dev(kb_dev); cprintk(rc_black, rc_magenta, "Init %s device ...\n\n", kb_dev->ops.get_desc()); } // 内核注册字符设备 int add_char_dev(char_dev_t *cdev) { char_dev_t *p = char_devs; while (p) { if (strcmp(p->name, cdev->name) == 0) { return -1; } p = p->next; } cdev->next = char_devs; char_devs = cdev; return 0; } ================================================ FILE: driver/device.c ================================================ /* * ===================================================================================== * * Filename: device.c * * Description: 外部设备相关 * * Version: 1.0 * Created: 2015年02月08日 11时47分59秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include // 外部设备初始化 void device_init(void) { char_dev_init(); block_dev_init(); } ================================================ FILE: driver/ide.c ================================================ /* * ===================================================================================== * * Filename: ide.c * * Description: IDE 设备驱动 * * Version: 1.0 * Created: 2015年02月03日 14时55分53秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #define SECTSIZE 512 // 默认扇区大小 /** * bit 7 = 1 控制器忙 * bit 6 = 1 驱动器就绪 * bit 5 = 1 设备错误 * bit 4 N/A * bit 3 = 1 扇区缓冲区错误 * bit 2 = 1 磁盘已被读校验 * bit 1 N/A * bit 0 = 1 上一次命令执行失败 */ #define IDE_BSY 0x80 // IDE驱动器忙 #define IDE_DRDY 0x40 // IDE驱动器就绪 #define IDE_DF 0x20 // IDE驱动器错误 #define IDE_ERR 0x01 // 上一次命令失败 #define IDE_CMD_READ 0x20 // IDE读扇区命令 #define IDE_CMD_WRITE 0x30 // IDE写扇区命令 #define IDE_CMD_IDENTIFY 0xEC // IDE识别命令 // IDE设备端口起始端口定义 #define IOBASE 0x1F0 // 主IDE设备起始操作端口 #define IOCTRL 0x3F4 // 主IDE控制起始控制端口 // IDE设备控制端口偏移量 #define ISA_DATA 0x00 // IDE数据端口偏移 #define ISA_ERROR 0x01 // IDE错误端口偏移 #define ISA_PRECOMP 0x01 #define ISA_CTRL 0x02 // IDE控制端口偏移 #define ISA_SECCNT 0x02 #define ISA_SECTOR 0x03 #define ISA_CYL_LO 0x04 #define ISA_CYL_HI 0x05 #define ISA_SDH 0x06 // IDE选择端口偏移 #define ISA_COMMAND 0x07 // IDE命令端口偏移 #define ISA_STATUS 0x07 // IDE状态端口偏移 // IDE设备限制值 #define MAX_NSECS 128 // IDE设备最大操作扇区数 #define MAX_DISK_NSECS 0x10000000 // IDE设备最大扇区号 // IDE设备身份信息在读取的信息块中的偏移 #define IDE_IDENT_SECTORS 20 #define IDE_IDENT_MODEL 54 #define IDE_IDENT_CAPABILITIES 98 #define IDE_IDENT_CMDSETS 164 #define IDE_IDENT_MAX_LBA 120 #define IDE_IDENT_MAX_LBA_EXT 200 #define IDE_DESC_LEN 40 // IDE设备描述信息尺寸 // IDE设备信息 static struct ide_device { uint8_t valid; // 是否可用 uint32_t sets; // 命令支持 uint32_t size; // 扇区数量 char desc[IDE_DESC_LEN+1]; // IDE设备描述 } ide_device; // 初始化IDE设备 static int ide_init(void); // 检测IDE设备是否可用 static bool ide_device_valid(void); // 获取IDE设备描述 static const char *ide_get_desc(void); // 获得设备默认块数量 static int ide_get_nr_block(void); // 设备操作请求 static int ide_request(io_request_t *req); // 读取IDE设备若干扇区 static int ide_read_secs(uint32_t secno, void *dst, uint32_t nsecs); // 写入IDE设备若干扇区 static int ide_write_secs(uint32_t secno, const void *src, uint32_t nsecs); // IDE设备选项设置 static int ide_ioctl(int op, int flag); // IDE 设备结构 block_dev_t ide_main_dev = { .name = "IDE_MAIN", .block_size = SECTSIZE, .ops = { .init = &ide_init, .device_valid = &ide_device_valid, .get_desc = &ide_get_desc, .get_nr_block = &ide_get_nr_block, .request = &ide_request, .ioctl = ide_ioctl } }; // 等待IDE设备可用 static int32_t ide_wait_ready(uint16_t iobase, bool check_error) { int r = 0; while ((r = inb(iobase + ISA_STATUS)) & IDE_BSY) { // Waiting ... Do nothing ... } if (check_error && (r & (IDE_DF | IDE_ERR)) != 0) { return -1; } return 0; } // 获取IDE设备描述 static const char *ide_get_desc(void) { return (const char *)(ide_device.desc); } // 初始化IDE设备 static int ide_init(void) { ide_wait_ready(IOBASE, 0); // 1: 选择要操作的设备 outb(IOBASE + ISA_SDH, 0xE0); ide_wait_ready(IOBASE, 0); // 2: 发送IDE信息获取命令 outb(IOBASE + ISA_COMMAND, IDE_CMD_IDENTIFY); ide_wait_ready(IOBASE, 0); // 3: 检查设备是否存在 if (inb(IOBASE + ISA_STATUS) == 0 || ide_wait_ready(IOBASE, 1) != 0) { return -1; } ide_device.valid = 1; // 读取IDE设备信息 uint32_t buffer[128]; insl(IOBASE + ISA_DATA, buffer, sizeof(buffer) / sizeof(uint32_t)); uint8_t *ident = (uint8_t *)buffer; uint32_t cmdsets = *(uint32_t *)(ident + IDE_IDENT_CMDSETS); uint32_t sectors; // 检查设备使用48-bits还是28-bits地址 if (cmdsets & (1 << 26)) { sectors = *(uint32_t *)(ident + IDE_IDENT_MAX_LBA_EXT); } else { sectors = *(uint32_t *)(ident + IDE_IDENT_MAX_LBA); } ide_device.sets = cmdsets; ide_device.size = sectors; char *desc = ide_device.desc; char *data = (char *)((uint32_t)ident + IDE_IDENT_MODEL); // 复制设备描述信息 int i, length = IDE_DESC_LEN; for (i = 0; i < length; i += 2) { desc[i] = data[i+1]; desc[i+1] = data[i]; } do { desc[i] = '\0'; } while (i-- > 0 && desc[i] == ' '); return 0; } // 检测指定IDE设备是否可用 static bool ide_device_valid(void) { return ide_device.valid == 1; } // 获得设备默认块数量 static int ide_get_nr_block(void) { if (ide_device_valid()) { return ide_device.size; } return 0; } // 设备操作请求 static int ide_request(io_request_t *req) { if (req->io_type == IO_READ) { if (req->bsize < SECTSIZE * req->nsecs) { return -1; } return ide_read_secs(req->secno, req->buffer ,req->nsecs); } else if (req->io_type == IO_WRITE) { if (req->bsize < SECTSIZE * req->nsecs) { return -1; } return ide_write_secs(req->secno, req->buffer ,req->nsecs); } return -1; } // 读取指定IDE设备若干扇区 static int ide_read_secs(uint32_t secno, void *dst, uint32_t nsecs) { assert(nsecs <= MAX_NSECS && ide_device.valid == 1, "nsecs or ide error!"); assert(secno < MAX_DISK_NSECS && secno + nsecs <= MAX_DISK_NSECS, "secno error!"); ide_wait_ready(IOBASE, 0); outb(IOCTRL + ISA_CTRL, 0); outb(IOBASE + ISA_SECCNT, nsecs); outb(IOBASE + ISA_SECTOR, secno & 0xFF); outb(IOBASE + ISA_CYL_LO, (secno >> 8) & 0xFF); outb(IOBASE + ISA_CYL_HI, (secno >> 16) & 0xFF); outb(IOBASE + ISA_SDH, 0xE0 | ((secno >> 24) & 0xF)); outb(IOBASE + ISA_COMMAND, IDE_CMD_READ); int ret = 0; for ( ; nsecs > 0; nsecs --, dst += SECTSIZE) { if ((ret = ide_wait_ready(IOBASE, 1)) != 0) { return ret; } insl(IOBASE, dst, SECTSIZE / sizeof(uint32_t)); } return ret; } // 写入指定IDE设备若干扇区 static int ide_write_secs(uint32_t secno, const void *src, uint32_t nsecs) { assert(nsecs <= MAX_NSECS && ide_device.valid == 1, "nsecs or ide error"); assert(secno < MAX_DISK_NSECS && secno + nsecs <= MAX_DISK_NSECS, "secno error!"); ide_wait_ready(IOBASE, 0); outb(IOCTRL + ISA_CTRL, 0); outb(IOBASE + ISA_SECCNT, nsecs); outb(IOBASE + ISA_SECTOR, secno & 0xFF); outb(IOBASE + ISA_CYL_LO, (secno >> 8) & 0xFF); outb(IOBASE + ISA_CYL_HI, (secno >> 16) & 0xFF); outb(IOBASE + ISA_SDH, 0xE0 | ((secno >> 24) & 0xF)); outb(IOBASE + ISA_COMMAND, IDE_CMD_WRITE); int ret = 0; for ( ; nsecs > 0; nsecs --, src += SECTSIZE) { if ((ret = ide_wait_ready(IOBASE, 1)) != 0) { return ret; } outsl(IOBASE, src, SECTSIZE / sizeof(uint32_t)); } return ret; } // IDE设备选项设置 static int ide_ioctl(int op, int flag) { if (op != 0 && flag != 0) { return -1; } return 0; } ================================================ FILE: driver/kboard.c ================================================ /* * ===================================================================================== * * Filename: kboard.c * * Description: 键盘驱动 * * Version: 1.0 * Created: 2015年02月05日 13时33分22秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include /* * 键盘当前状态信息(相关位被设置即为有效) * * 0: control * 1: alt * 2: alt-gr * 3: left shift * 4: right shift * 5: caps_lock * 6: scroll_lock * 7: num_lock */ #define CONTROL 0x1 #define ALT 0x2 #define ALTGR 0x4 #define LSHIFT 0x8 #define RSHIFT 0x10 #define CAPSLOCK 0x20 #define SCROLLLOCK 0x40 #define NUMLOCK 0x80 // 8 位的键盘扫描码的接通码使用前7位 // 其最高位置 1 即是其对应的断开码 // 该宏可以和获取的扫描码用来判断一个键是按下还是抬起 #define RELEASED_MASK 0x80 typedef uint8_t key_status_t; typedef struct keymap { uint8_t scancodes[128]; // 键盘扫描码的映射 uint8_t capslock_scancodes[128]; uint8_t shift_scancodes[128]; uint8_t control_map[8]; key_status_t controls; // 键盘的控制状态信息 } keymap_t; static keymap_t us_keymap = { //normal keys { /* first row - indices 0 to 14 */ 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', /* second row - indices 15 to 28 */ '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', //Enter key /* 29 = Control, 30 - 41: third row */ 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', /* fourth row, indices 42 to 54, zeroes are shift-keys*/ 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, '*', /* Special keys */ 0, // ALT - 56 ' ', // Space - 57 0, // Caps lock - 58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F1 to F10 - 59 to 68 0, // Num lock - 69 0, // Scroll lock - 70 0, // Home - 71 72, // Up arrow - 72 TODO 0, // Page up - 73 '-', 0, // Left arrow - 75 0, 0, // Right arrow -77 '+', 0, // End - 79 80, // Dowm arrow - 80 TODO 0, // Page down - 81 0, // Insert - 82 0, // Delete - 83 0, 0, 0, 0, // F11 - 87 0, // F12 - 88 0, // All others undefined }, // caps { /* first row - indices 0 to 14 */ 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', /* second row - indices 15 to 28 */ '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* 29 = Control, 30 - 41: third row */ 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', '`', /* fourth row, indices 42 to 54, zeroes are shift-keys*/ 0, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 0, '*', /* Special keys */ 0, // ALT - 56 ' ', // Space - 57 0, // Caps lock - 58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F1 to F10 - 59 to 68 0, // Num lock - 69 0, // Scroll lock - 70 0, // Home - 71 0, // Up arrow - 72 0, // Page up - 73 '-', 0, // Left arrow - 75 0, 0, // Right arrow -77 '+', 0, // End - 79 0, // Dowm arrow - 80 0, // Page down - 81 0, // Insert - 82 0, // Delete - 83 0, 0, 0, 0, // F11 - 87 0, // F12 - 88 0, // All others undefined }, // shift { /* first row - indices 0 to 14 */ 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', /* second row - indices 15 to 28 */ '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* 29 = Control, 30 - 41: third row */ 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', /* fourth row, indices 42 to 54, zeroes are shift-keys*/ 0, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, '*', /* Special keys */ 0, // ALT - 56 ' ', // Space - 57 0, // Caps lock - 58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F1 to F10 - 59 to 68 0, // Num lock - 69 0, // Scroll lock - 70 0, // Home - 71 0, // Up arrow - 72 0, // Page up - 73 '-', 0, // Left arrow - 75 0, 0, // Right arrow -77 '+', 0, // End - 79 0, // Dowm arrow - 80 0, // Page down - 81 0, // Insert - 82 0, // Delete - 83 0, 0, 0, 0, // F11 - 87 0, // F12 - 88 0, // All others undefined }, // control_map { 29, // Ctrl 56, // Alt 0, // AltGr 42, // left Shift 54, // right Shift 58, // Caps lock 70, // Scroll lock 69 // Num lock }, // 键盘的控制键信息初始化为 0 0 }; // 设备初始化 static int kb_init(void); // 设备是否可用 static bool kb_device_valid(void); // 获取设备描述 static const char *kb_get_desc(void); // 设备读取 static int kb_read(void *dec, uint32_t len); // 设备写入 static int kb_write(const void *src, uint32_t len); // 设备控制 static int kb_ioctl(int op, int flag); // 键盘中断处理函数 static void keyboard_handler(__UNUSED__ pt_regs_t *regs); // Keyboard 设备结构 char_dev_t kboard_dev = { .name = "Keyboard", .is_readable = true, .is_writeable = false, .ops = { .init = kb_init, .device_valid = kb_device_valid, .get_desc = kb_get_desc, .read = kb_read, .write = kb_write, .ioctl = kb_ioctl } }; #define KBUFFER_LEN 1024 // Keyboard 管理信息 static struct kboard_device { bool is_valid; // 设备是否可用 keymap_t *curr_layout; // 当前的字符集 uint8_t kbuffer[KBUFFER_LEN]; // 键盘输入的缓冲区队列 uint32_t kfront; // 缓冲队列队头 uint32_t krear; // 缓冲队列队尾 } kb_device; // 设备初始化 static int kb_init(void) { // 采用US字符集 kb_device.curr_layout = &us_keymap; // 设置设备可用 kb_device.is_valid = true; // 注册键盘中断处理函数 register_interrupt_handler(IRQ1, &keyboard_handler); return 0; } // 设备是否可用 static bool kb_device_valid(void) { return kb_device.is_valid; } // 获取设备描述 static const char *kb_get_desc(void) { return "Keyboard"; } static uint8_t kb_getchar(void) { // 队列中有数据则取出,否则返回 0 if (kb_device.kfront != kb_device.krear) { char ch = kb_device.kbuffer[kb_device.kfront]; kb_device.kfront = (kb_device.kfront + 1) % KBUFFER_LEN; return ch; } else { return 0; } } // 设备读取 static int kb_read(void *dec, uint32_t len) { uint8_t *buffer = (uint8_t *)dec; uint8_t ch = 0; uint32_t i = 0; while (i < len) { if ((ch = kb_getchar()) != 0) { buffer[i] = ch; i++; } else { break; } } return i; } // 设备写入 static int kb_write(__UNUSED__ const void *src, __UNUSED__ uint32_t len) { return -1; } // 键盘中断处理函数 static void keyboard_handler(__UNUSED__ pt_regs_t *regs) { // 从键盘端口读入按下的键 uint8_t scancode = inb(0x60); keymap_t *layout = kb_device.curr_layout; // 首先判断是按下还是抬起 if (scancode & RELEASED_MASK) { uint32_t i; // 我们只检查前 5 个控制键,因为前五位 Ctrl Alt Shift 松开后不保留状态 // 所以这些按键松开后必须清除按下标记 for (i = 0; i < 5; i++) { if(layout->control_map[i] == (scancode & ~RELEASED_MASK)) { layout->controls &= ~(1 << i); return; } } // 当键被按下 } else { uint32_t i; // 逐一检查各个控制位 for (i = 0; i < 8; i++) { // 如果当前键是控制键,则给相关控制位置 1 // 如果已有该标志位,则给相关控制位清 0 if (layout->control_map[i] == scancode) { if (layout->controls & 1 << i) { layout->controls &= ~(1 << i); } else { layout->controls |= (1 << i); } return; } } uint8_t *scancodes = layout->scancodes; // 如果此时按下了 shift 键,切换到 shift 扫描码 if ((layout->controls & (LSHIFT | RSHIFT)) && !(layout->controls & CONTROL)) { scancodes = layout->shift_scancodes; } // 如果此时处于大写锁定状态,切换到大写锁定的扫描码 if ((layout->controls & (CAPSLOCK)) && !(layout->controls & CONTROL)) { scancodes = layout->capslock_scancodes; } // 如果队列不满则字符入队,否则丢弃 if (kb_device.kfront != (kb_device.krear + 1) % KBUFFER_LEN) { kb_device.kbuffer[kb_device.krear] = scancodes[scancode]; kb_device.krear = (kb_device.krear + 1) % KBUFFER_LEN; } } } // 设备控制 static int kb_ioctl(int op, int flag) { if (op != 0 && flag != 0) { return -1; } return 0; } ================================================ FILE: fs/fs.c ================================================ /* * ===================================================================================== * * Filename: fs.c * * Description: 文件系统相关 * * Version: 1.0 * Created: 2015年02月08日 10时07分54秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include // vfs 初始化 void vfs_init(void); // sfs 文件系统初始化 void sfs_init(void); // 文件系统初始化 void fs_init(void) { vfs_init(); device_init(); sfs_init(); } ================================================ FILE: fs/mbr.c ================================================ /* * ===================================================================================== * * Filename: mbr.c * * Description: MBR 相关 * * Version: 1.0 * Created: 2015年02月08日 11时07分54秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include // MBR信息 mbr_info_t mbr_info; // 读取分区信息 int read_mbr_info(block_dev_t *bdev) { io_request_t request; request.io_type = IO_READ; request.secno = 0; request.nsecs = 1; request.buffer = &mbr_info; request.bsize = sizeof(mbr_info); if (bdev->ops.request(&request) == 0) { return 0; } return -1; } void show_partition_info(void) { cprintk(rc_black, rc_red, "\nPartition Info:\n"); for (int i = 0; i < PARTITION_COUNT; ++i) { if (mbr_info.part[i].partition_type != 0) { cprintk(rc_black, rc_red, "Active: %02X ", mbr_info.part[i].active_flag); cprintk(rc_black, rc_red, "Type: %02X ", mbr_info.part[i].partition_type); cprintk(rc_black, rc_red, "SCHS: %02X%02X%02X ", mbr_info.part[i].start_chs[0], mbr_info.part[i].start_chs[1], mbr_info.part[i].start_chs[2]); cprintk(rc_black, rc_red, "ECHS: %02X%02X%02X ", mbr_info.part[i].end_chs[0], mbr_info.part[i].end_chs[1], mbr_info.part[i].end_chs[2]); cprintk(rc_black, rc_red, "Start: %04u ", mbr_info.part[i].start_sector); cprintk(rc_black, rc_red, "Count: %05u\n", mbr_info.part[i].nr_sectors); } } } ================================================ FILE: fs/ramfs/ramfs.c ================================================ /* * ===================================================================================== * * Filename: ramfs.c * * Description: 根文件系统 * * Version: 1.0 * Created: 2015年02月10日 12时06分50秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include // 读取super_block static struct super_block *ramfs_read_super(struct super_block *sb); // ramfs 定义 struct filesystem fs_ramfs = { .name = "ramfs", .type = RAMFS_T, .read_super = ramfs_read_super }; // 申请 inode static struct inode *ramfs_alloc_inode(struct super_block *sb); // 释放inode static void ramfs_destroy_inode(struct inode *inode); // 设备写回超级块 static void ramfs_write_super(struct super_block *sb); // 同步文件系统修改 static int ramfs_sync_fs(struct super_block *sb); // super_block_ops 定义 static struct super_block_ops ramfs_sb_ops = { .alloc_inode = ramfs_alloc_inode, .destroy_inode = ramfs_destroy_inode, .write_super = ramfs_write_super, .sync_fs = ramfs_sync_fs, }; // 读取super_block static struct super_block *ramfs_read_super(struct super_block *sb) { sb->s_type = RAMFS_T; sb->s_ops = &ramfs_sb_ops; return sb; } // 申请 inode static struct inode *ramfs_alloc_inode(__UNUSED__ struct super_block *sb) { return alloc_inode(); } // 释放inode static void ramfs_destroy_inode(struct inode *inode) { free_inode(inode); } // 设备写回超级块 static void ramfs_write_super(__UNUSED__ struct super_block *sb) { // do nothing ... } // 同步文件系统修改 static int ramfs_sync_fs(__UNUSED__ struct super_block *sb) { // do nothing ... return 0; } ================================================ FILE: fs/sfs/sfs.c ================================================ /* * ===================================================================================== * * Filename: sfs.c * * Description: simple file system * * Version: 1.0 * Created: 2015年02月10日 14时09分46秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #include #include #include #define SUPER_BLOCK_OFFSET 4 // super_block 偏移 #define INODEMAP_OFFSET 12 // inode_map 偏移 // block 默认大小 #define BLOCK_SIZE 2048 // 最大文件大小 #define MAX_FILE_SIZE (P_BLOCK_MAP_SIZE * BLOCK_SIZE + \ PP_BLOCK_MAP_SIZE * (BLOCK_SIZE / sizeof(uint32_t)) * BLOCK_SIZE) // SFS 文件系统的 super_block static struct super_block *sfs_sb; // SFS 文件系统的 inode_map static uint8_t *sfs_inode_map; // SFS 文件系统的 block_map static uint8_t *sfs_block_map; // SFS 文件系统的 inode cache static uint8_t **inode_cache; // SFS 文件系统的 block cache static uint8_t **block_cache; // 初始化文件系统 static void sfs_mkfs(uint32_t start_sec, uint32_t end_sec, uint32_t block_size); // 读取super_block static struct super_block *sfs_read_super(struct super_block *sb); // 回写 super_block static void sfs_write_super(struct sfs_super_block *sb); // 读取 inode_map static int sfs_read_inode_map(void); // 回写 inode_map static void sfs_write_inode_map(void); // 读取 block_map static int sfs_read_block_map(void); // 回写 block_map static void sfs_write_block_map(void); // 申请 inode 号 static uint32_t sfs_alloc_inode(void); // 释放 inode 号 static void sfs_free_inode(uint32_t inode_no); // 申请 block 号 static uint32_t sfs_alloc_block(void); // 释放 block 号 static void sfs_free_block(uint32_t block_no); // 读取 inode // static struct sfs_inode *sfs_read_inode(uint32_t inode_no); // 获取 inode 数据指针(从 inode_cache 获取,可能阻塞于磁盘IO) static uint8_t *sfs_read_inode(uint32_t inode_no); // 获取 blcok 指针(从 block_cache 获取,可能阻塞于磁盘IO) static uint8_t *sfs_read_block(uint32_t block_no); // sfs 定义 struct filesystem fs_sfs = { .name = "sfs", .type = SFS_T, .read_super = sfs_read_super }; // sfs 文件系统初始化 void sfs_init(void) { cprintk(rc_black, rc_cyan, "\nInit SFS Filesystem ...\n"); if (add_filesystem(&fs_sfs) == -1) { printk("Add SFS Filesystem Error!\n"); } uint32_t start_sec = 0; uint32_t end_sec = 0; for (int i = 0; i < PARTITION_COUNT; ++i) { if (mbr_info.part[i].partition_type == SFS_T) { cprintk(rc_black, rc_cyan, "Found SFS Filesystem Partition: "); cprintk(rc_black, rc_cyan, "Start: %u Count: %u\n\n", mbr_info.part[i].start_sector, mbr_info.part[i].nr_sectors); start_sec = mbr_info.part[i].start_sector; end_sec = mbr_info.part[i].nr_sectors; } } if (start_sec > 0 && end_sec > 0 && end_sec > start_sec) { sfs_mkfs(start_sec, end_sec, BLOCK_SIZE); } } // 初始化文件系统 static void sfs_mkfs(uint32_t start_sec, uint32_t end_sec, uint32_t block_size) { uint32_t sb_start = start_sec + SUPER_BLOCK_OFFSET; // super_block 起始扇区 uint32_t all_sec = end_sec - start_sec - INODEMAP_OFFSET; // 可用扇区数 // inode : block = 1 : 9 uint32_t in_secs = all_sec / 10; // inode 所占扇区数 uint32_t bl_secs = all_sec / 10 * 9; // block 所占扇区数 uint32_t in_count = in_secs; // inode 数量 uint32_t bl_count = bl_secs / (block_size / 512); // block 数量 uint32_t im_start = start_sec + INODEMAP_OFFSET; // inode map 起始 uint32_t im_secs = in_secs / 512 + 1; // inode map 所占扇区数 uint32_t bm_start = im_start + im_secs; // block map 起始地址 uint32_t bm_secs = bl_secs / block_size + 1; // block map 所占扇区数 uint32_t in_start = bm_start + bm_secs; // inode 起始位置 uint32_t bl_start = in_start + in_secs; // block 起始位置 printk("super_block start: %u\n", sb_start); printk("all secs: %u\n\n", all_sec); printk("inode_map start: %u\n", im_start); printk("inode_map secs: %u\n\n", im_secs); printk("block_map start: %u\n", bm_start); printk("block_map secs: %u\n\n", bm_secs); printk("inode start: %u\n", in_start); printk("inode secs: %u\n", in_secs); printk("inode count: %u\n\n", in_count); printk("block start: %u\n", bl_start); printk("block secs: %u\n", bl_secs); printk("block count: %u\n\n", bl_count); printk("max file size: %u B ~= %d MB\n\n", MAX_FILE_SIZE, MAX_FILE_SIZE / 1024 / 1024); struct sfs_super_block sfs_sb; bzero(&sfs_sb, sizeof(sfs_sb)); sfs_sb.s_type = SFS_T; sfs_sb.s_inode_count = in_count; sfs_sb.s_block_count = bl_count; sfs_sb.s_block_size = block_size; sfs_sb.s_max_file = MAX_FILE_SIZE; sfs_sb.s_root_inode = 0; sfs_sb.in_secs = in_secs; sfs_sb.bl_secs = bl_secs; sfs_sb.im_start = im_start; sfs_sb.im_secs = im_secs; sfs_sb.bm_start = bm_start; sfs_sb.bm_secs = bm_secs; sfs_sb.in_start = in_start; sfs_sb.bl_start = bl_start; } // 读取super_block static struct super_block *sfs_read_super(struct super_block *sb) { sfs_sb = NULL; return NULL; } // 回写 super_block static void sfs_write_super(struct sfs_super_block *sb) { } // 读取 inode_map static int sfs_read_inode_map(void) { sfs_inode_map = NULL; return 0; } // 回写 inode_map static void sfs_write_inode_map(void) { } // 读取 block_map static int sfs_read_block_map(void) { sfs_block_map = NULL; return 0; } // 回写 block_map static void sfs_write_block_map(void) { } // 申请 inode 号 static uint32_t sfs_alloc_inode(void) { return 0; } // 释放 inode 号 static void sfs_free_inode(uint32_t inode_no) { } // 申请 block 号 static uint32_t sfs_alloc_block(void) { return 0; } // 释放 block 号 static void sfs_free_block(uint32_t block_no) { } // 获取 inode 数据指针(从 inode_cache 获取,可能阻塞于磁盘IO) static uint8_t *sfs_read_inode(uint32_t inode_no) { return NULL; } // 获取 blcok 指针(从 block_cache 获取,可能阻塞) static uint8_t *sfs_read_block(uint32_t block_no) { return NULL; } ================================================ FILE: fs/sfs/sfs.h ================================================ /* * ===================================================================================== * * Filename: sfs.h * * Description: simple file system * * Version: 1.0 * Created: 2015年06月02日 10时09分46秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef FS_SFS_SFS_H #define FS_SFS_SFS_H #include struct sfs_super_block { uint16_t s_type; // 文件系统类型 uint32_t s_inode_count; // inode数量 uint32_t s_block_count; // block数量 uint32_t s_block_size; // block大小 uint32_t s_max_file; // 文件最大尺寸 uint32_t s_root_inode; // 根目录 inode 号 uint32_t in_secs; // inode 所占扇区数 uint32_t bl_secs; // block 所占扇区数 uint32_t im_start; // inode map 起始 uint32_t im_secs; // inode map 所占扇区数 uint32_t bm_start; // block map 起始地址 uint32_t bm_secs; // block map 所占扇区数 uint32_t in_start; // inode 起始位置 uint32_t bl_start; // block 起始位置 }; #define P_BLOCK_MAP_SIZE 32 // 一级 block 数量 #define PP_BLOCK_MAP_SIZE 32 // 二级 block 数量 struct sfs_inode { uint32_t i_type; // inode 类型 uint32_t i_ino; // 索引节点号 time_t i_atime; // 文件最后一次访问时间 time_t i_mtime; // 文件最后一次修改时间 time_t i_ctime; // 文件首次创建时间 uint32_t i_size; // 文件字节数 uint32_t i_blocks; // 文件使用block数 uint32_t i_bytes; // 文件最后一个block的字节数 uint32_t p_block_map[P_BLOCK_MAP_SIZE]; // 一级 block 指向 uint32_t pp_block_map[PP_BLOCK_MAP_SIZE]; // 二级 block 指向 }; // 最长文件名 #define SFS_MAX_FILE_NAME 123 // 目录类型inode存储的目录数据块 sizeof = 128 struct sfs_dirent { char d_name[SFS_MAX_FILE_NAME+1]; // 目录项名称 uint32_t inode; // 对应的 inode 号 }; #endif // FS_SFS_SFS_H ================================================ FILE: fs/vfs.c ================================================ /* * ===================================================================================== * * Filename: vfs.c * * Description: 虚拟文件系统 * * Version: 1.0 * Created: 2015年02月06日 10时15分38秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #include #include #include // 全局的文件系统指针 struct filesystem *file_systems; // 初始化VFS目录树 static void init_mount_tree(struct vfsmount *mount); // vfs 初始化 void vfs_init(void) { cprintk(rc_black, rc_light_brown, "Init Virtual File System ...\n\n"); struct vfsmount *mount; mount = kmalloc(sizeof(struct vfsmount)); assert(mount != NULL, "vfs_init alloc vfsmount failed!"); // 初始化VFS目录树 init_mount_tree(mount); current->files.vfsmount = mount; } // 初始化VFS目录树 static void init_mount_tree(struct vfsmount *mount) { // 添加根文件系统 add_filesystem(&fs_ramfs); INIT_LIST_HEAD(&(fs_ramfs.fs_supers)); // 获取根文件系统的超级块结构 struct super_block *sb = alloc_super_block(); bzero(sb, sizeof(struct super_block)); // 将 super_block 添加到文件系统控制信息下 list_add(&(sb->s_list), &(fs_ramfs.fs_supers)); // 为根文件系统初始化超级块 fs_ramfs.read_super(sb); // 初始化根结点 inode struct inode *inode = alloc_inode(); bzero(inode, sizeof(struct inode)); inode->i_sb = sb; // 初始化根结点 dentry struct dentry *dentry = alloc_dentry(); atomic_set(&(dentry->d_count), 0); INIT_LIST_HEAD(&(dentry->d_subdirs)); INIT_LIST_HEAD(&(dentry->d_child)); dentry->d_status = 1; dentry->d_parent = NULL; dentry->d_sb = sb; dentry->d_inode = inode; dentry->is_mounted = 0; strcpy(dentry->d_name, "/"); // 链接根节点 dentry sb->s_root = dentry; mount->mnt_devname = "RAM"; mount->mnt_sb = sb; mount->mnt_root = dentry; mount->mnt_mountpoint = dentry; mount->mnt_parent = NULL; } // 添加文件系统 int add_filesystem(struct filesystem *fs) { struct filesystem *p = file_systems; while (p) { if (strcmp(p->name, fs->name) == 0) { return -1; } p = p->next; } fs->next = file_systems; file_systems = fs; return 0; } struct super_block *alloc_super_block(void) { struct super_block *sb; sb = kmalloc(sizeof(struct super_block)); assert(sb != NULL, "alloc super_block failed!"); return sb; } struct super_block_ops *alloc_super_block_ops(void) { struct super_block_ops *sb_ops; sb_ops = kmalloc(sizeof(struct super_block_ops)); assert(sb_ops != NULL, "alloc super_block_ops failed!"); return sb_ops; } struct inode *alloc_inode(void) { struct inode *inode; inode = kmalloc(sizeof(struct inode)); assert(inode != NULL, "alloc inode failed!"); return inode; } struct inode_ops *alloc_inode_ops(void) { struct inode_ops *inode_ops; inode_ops = kmalloc(sizeof(struct inode_ops)); assert(inode_ops != NULL, "alloc inode_ops failed!"); return inode_ops; } struct dentry *alloc_dentry(void) { struct dentry *dentry; dentry = kmalloc(sizeof(struct dentry)); assert(dentry != NULL, "alloc dentry failed!"); return dentry; } struct dentry_ops *alloc_dentry_ops(void) { struct dentry_ops *dentry_ops; dentry_ops = kmalloc(sizeof(struct dentry_ops)); assert(dentry_ops != NULL, "alloc dentry_ops failed!"); return dentry_ops; } struct file *alloc_file(void) { struct file *file; file = kmalloc(sizeof(struct file)); assert(file != NULL, "alloc file failed!"); return file; } struct file_ops *alloc_file_ops(void) { struct file_ops *file_ops; file_ops = kmalloc(sizeof(struct file_ops)); assert(file_ops != NULL, "alloc file_ops failed!"); return file_ops; } void free_super_block(struct super_block *sb) { assert(sb != NULL, "free_super_block error, sb is NULL!"); kfree(sb); } void free_super_block_ops(struct super_ops *sb_ops) { assert(sb_ops != NULL, "free_super_block_ops error, sb_ops is NULL!"); kfree(sb_ops); } void free_inode(struct inode *inode) { assert(inode != NULL, "free_inode error, inode is NULL!"); kfree(inode); } void free_inode_ops(struct inode_ops *inode_ops) { assert(inode_ops != NULL, "free_inode_ops error, inode_ops is NULL!"); kfree(inode_ops); } void free_dentry(struct dentry *dentry) { assert(dentry != NULL, "free_dentry error, dentry is NULL!"); kfree(dentry); } void free_dentry_ops(struct dentry_ops *dentry_ops) { assert(dentry_ops != NULL, "free_dentry_ops error, detry_ops is NULL!"); kfree(dentry_ops); } void free_file(struct file *file) { assert(file != NULL, "free_file error, file is NULL!"); kfree(file); } void free_file_ops(struct file_ops *file_ops) { assert(file_ops != NULL, "free_file_ops error, file_ops is NULL!"); kfree(file_ops); } // 打开文件 int vfs_open(const char *filename, uint32_t openflag) { if (!filename || !openflag) { return 0; } return 0; } // 关闭文件 int vfs_close(int fd) { return fd; } // 读取文件 int vfs_read(int fd, char *buff, size_t size) { if (!buff || !size) { return 0; } return fd; } // 写入文件 int vfs_write(int fd, const char *buff, size_t size) { if (!buff || !size) { return 0; } return fd; } ================================================ FILE: include/block_dev.h ================================================ /* * ===================================================================================== * * Filename: block_dev.h * * Description: 块设备接口定义 * * Version: 1.0 * Created: 2015年02月07日 11时15分49秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_BLOCK_DEV_H_ #define INCLUDE_BLOCK_DEV_H_ #include typedef enum io_type { IO_READ = 0, IO_WRITE = 1 } io_type_t; typedef struct io_request { io_type_t io_type; // IO操作类型 uint32_t secno; // 起始位置 uint32_t nsecs; // 读写数量 void *buffer; // 读写缓冲区 uint32_t bsize; // 缓冲区尺寸 } io_request_t; // 块设备接口 typedef struct block_dev { const char *name; // 设备名称 uint32_t block_size; // 单位块大小 struct block_ops { // 设备操作 int (*init)(void); // 设备初始化 bool (*device_valid)(void); // 设备是否可用 const char *(*get_desc)(void); // 获取设备描述 int (*get_nr_block)(void); // 获得设备默认块数量 int (*request)(io_request_t *); // 设备操作请求 int (*ioctl)(int, int); // 设备选项设置 } ops; struct block_dev *next; // 块设备链 } block_dev_t; // 全局块设备链表 extern block_dev_t *block_devs; // 块设备初始化 void block_dev_init(void); // 内核注册块设备 int add_block_dev(block_dev_t *bdev); // IDE 设备结构 extern block_dev_t ide_main_dev; #endif // INCLUDE_BLOCK_DEV_H_ ================================================ FILE: include/char_dev.h ================================================ /* * ===================================================================================== * * Filename: char_dev.h * * Description: 字符设备定义 * * Version: 1.0 * Created: 2015年02月07日 11时16分28秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_CHAR_DEV_H_ #define INCLUDE_CHAR_DEV_H_ #include // 字符设备接口 typedef struct char_dev { const char *name; // 设备名称 bool is_readable; // 设备是否可读 bool is_writeable; // 设备是否可写 struct char_ops { // 设备操作 int (*init)(void); // 设备初始化 bool (*device_valid)(void); // 设备是否可用 const char *(*get_desc)(void); // 获取设备描述 int (*read)(void *, uint32_t); // 设备读取 int (*write)(const void *, uint32_t); // 设备写入 int (*ioctl)(int, int); // 设备选项设置 } ops; struct char_dev *next; // 字符设备链 } char_dev_t; // 全局字符设备链表 extern char_dev_t *char_devs; // 字符设备初始化 void char_dev_init(void); // 内核注册字符设备 int add_char_dev(char_dev_t *cdev); // Keyboard 设备结构 extern char_dev_t kboard_dev; #endif // INCLUDE_CHAR_DEV_H_ ================================================ FILE: include/debug.h ================================================ /* * ===================================================================================== * * Filename: debug.h * * Description: 调试函数 * * Version: 1.0 * Created: 2014年11月04日 11时45分02秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_DEBUG_H_ #define INCLUDE_DEBUG_H_ #include #include #include #include // 内核代码段在内存中的起始和结束位置,在链接脚本中定义 extern uint8_t kern_init_text_start[]; extern uint8_t kern_init_text_end[]; extern uint8_t kern_init_data_start[]; extern uint8_t kern_init_data_end[]; extern uint8_t kern_text_start[]; extern uint8_t kern_text_end[]; extern uint8_t kern_data_start[]; extern uint8_t kern_data_end[]; #define assert(x, info) \ do { \ if (!(x)) { \ panic(info); \ } \ } while (0) // 初始化 Debug 信息 void debug_init(void); // 输出 BIOS 提供的物理内存布局 void show_memory_map(void); // 输出内核当前占据的内存地址 void show_kernel_memory_map(void); // 打印当前的函数调用栈信息 void panic(const char *msg); // 打印当前的段存器值 void print_cur_status(void); // 内核的打印函数 void printk(const char *format, ...); // 内核的打印函数(带颜色) void cprintk(real_color_t back, real_color_t fore, const char *format, ...); #endif // INCLUDE_DEBUG_H_ ================================================ FILE: include/device.h ================================================ /* * ===================================================================================== * * Filename: device.h * * Description: 外部设备相关 * * Version: 1.0 * Created: 2015年02月08日 11时46分35秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_DEVICE_H_ #define INCLUDE_DEVICE_H_ // 外部设备初始化 void device_init(void); #endif // INCLUDE_DEVICE_H_ ================================================ FILE: include/elf.h ================================================ /* * ===================================================================================== * * Filename: elf.h * * Description: elf 相关的定义 * * Version: 1.0 * Created: 2014年11月04日 11时00分18秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_ELF_H_ #define INCLUDE_ELF_H_ #include #include #define ELF32_ST_TYPE(i) ((i)&0xf) // ELF 格式区段头 typedef struct elf_section_header_t { uint32_t name; uint32_t type; uint32_t flags; uint32_t addr; uint32_t offset; uint32_t size; uint32_t link; uint32_t info; uint32_t addralign; uint32_t entsize; } __attribute__((packed)) elf_section_header_t; // ELF 格式符号 typedef struct elf_symbol_t { uint32_t name; uint32_t value; uint32_t size; uint8_t info; uint8_t other; uint16_t shndx; } __attribute__((packed)) elf_symbol_t; // ELF 信息 typedef struct elf_t { elf_symbol_t *symtab; uint32_t symtabsz; const char *strtab; uint32_t strtabsz; } elf_t; #endif // INCLUDE_ELF_H_ ================================================ FILE: include/errno.h ================================================ /* * ===================================================================================== * * Filename: errno.h * * Description: 错误编号 * * Version: 1.0 * Created: 2014年11月12日 15时22分53秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_ERRNO_H_ #define INCLUDE_ERRNO_H_ #include #define E_UNSPECIFIED 1 // Unspecified or unknown problem #define E_BAD_PROC 2 // Process doesn't exist or otherwise #define E_INVAL 3 // Invalid parameter #define E_NO_MEM 4 // Request failed due to memory shortage #define E_NO_FREE_PROC 5 // Attempt to create a new process beyond #define E_FAULT 6 // Memory fault #define MAXERROR 6 // 获得错误号对应的字符串 const char *strerr(int errno); #endif // INCLUDE_ERRNO_H_ ================================================ FILE: include/fs.h ================================================ /* * ===================================================================================== * * Filename: fs.h * * Description: 文件系统相关 * * Version: 1.0 * Created: 2015年02月08日 10时07分14秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_FS_H_ #define INCLUDE_FS_H_ #include #include #include #define RAMFS_T 0xA0 #define SFS_T 0xAA // 前置声明 struct super_block; struct super_ops; struct inode; struct inode_ops; struct dentry; struct dentry_ops; struct file; struct file_ops; struct filesystem { const char *name; // 文件系统名称 uint8_t type; // 文件系统类型 struct super_block *(*read_super)(struct super_block *); // 读取super_block struct list_head fs_supers; // super_block指针 struct filesystem *next; // 下一个文件系统 }; struct super_block { uint16_t s_type; // 文件系统类型 uint32_t s_inode_count; // inode数量 uint32_t s_block_count; // block数量 uint32_t s_block_size; // block大小 uint32_t s_max_file; // 文件最大尺寸 uint32_t s_root_inode; // 根 inode void *impl_sb; // 指向具体文件系统的 super_block struct list_head s_list; // super_block指针 block_dev_t *bdev; // 对应的块设备指针 struct dentry *s_root; // 根dentry struct super_block_ops *s_ops; // super_block操作 }; struct super_block_ops { struct inode *(*alloc_inode)(struct super_block *); // 获取inode void (*destroy_inode)(struct inode *); // 释放inode void (*write_super)(struct super_block *); // 写回super_block int (*sync_fs)(struct super_block *); // 同步文件系统 }; #define S_DIR 0x1 // inode 目录类型 #define S_FILE 0x2 // inode 文件类型 struct inode { uint32_t i_type; // inode 类型 uint32_t i_ino; // 索引节点号 time_t i_atime; // 文件最后一次访问时间 time_t i_mtime; // 文件最后一次修改时间 time_t i_ctime; // 文件首次创建时间 uint32_t i_size; // 文件字节数 uint32_t i_blocks; // 文件使用block数 uint32_t i_bytes; // 文件最后一个block的字节数 void *impl_in; // 指向具体文件系统的 inode spinlock_t i_lock; // inode自旋锁 atomic_t i_count; // 索引节点引用计数 struct super_block *i_sb; // super_blcok指针 struct list_head i_list; // inode 链 }; // inode相关操作 struct inode_ops { int (*create)(struct inode *, struct dentry *); // 创建文件 int (*rm)(struct inode *, struct dentry *); // 删除文件 int (*mkdir)(struct inode *, struct dentry *); // 创建目录 int (*rmdir)(struct inode *, struct dentry *); // 删除目录 int (*rename)(struct inode *, struct dentry *, // 重命名 struct inode *, struct dentry *); }; // 最长文件名 #define MAX_FILE_NAME 123 // 目录类型inode存储的目录数据块 sizeof = 128 struct dirent { char d_name[MAX_FILE_NAME+1]; // 目录项名称 uint32_t inode; // 对应的 inode }; struct dentry { atomic_t d_count; // 引用计数 spinlock_t d_lock; // dentry项的自旋锁 char d_name[MAX_FILE_NAME+1]; // 目录项名称 uint32_t d_status; // 目录项状态 struct dentry *d_parent; // 父目录指针 struct list_head d_subdirs; // 子目录链表头 struct list_head d_child; // 链接到父dentry的d_subdirs bool is_mounted; // 是否被挂载设备 struct super_block *d_sb; // 目录项对应的super_blcok struct inode *d_inode; // 链接到目录项对应的inode struct dentry_ops *d_ops; // dentry相关操作 }; struct dentry_ops { int (*del)(struct dentry *); }; // 最长路径长度(含文件名) #define MAX_PATH 1024 struct file { atomic_t f_count; // 引用计数 spinlock_t f_lock; // file项的自旋锁 char f_path[MAX_PATH+1]; // 文件路径 struct dentry *f_dentry; // 与文件相关的dentry uint32_t f_openflag; // 打开文件时的标记 uint32_t f_pos; // 文件操作的偏移 struct file_ops *f_ops; // 文件操作 }; struct file_ops { int (*read)(struct file *, char *, uint32_t); int (*write)(struct file *, const char *, uint32_t); int (*open)(struct inode *, struct file *); int (*fsync)(struct file *); int (*close)(struct inode *, struct file *); }; // 进程最大打开的文件个数 #define MAX_OPEN_FILE 64 // 进程PCB里描述文件系统的结构 struct file_struct { spinlock_t fs_lock; // 同步修改保护锁 struct vfsmount *vfsmount; // 文件系统根结构 struct file *file_array[MAX_OPEN_FILE]; // 进程打开的文件描述 }; struct vfsmount { const char *mnt_devname; // 挂载的设备名称 struct super_block *mnt_sb; // 挂载的 super_block struct dentry *mnt_root; // 挂载的根目录 dentry struct dentry *mnt_mountpoint; // 挂载点 dentry struct vfsmount *mnt_parent; // 父vfsmount指针 }; // 全局的文件系统指针 extern struct filesystem *file_systems; // 根文件系统 extern struct filesystem fs_ramfs; // 文件系统初始化 void fs_init(void); // 内核注册文件系统 int add_filesystem(struct filesystem *fs); // 获取 super_block 结构 struct super_block *alloc_super_block(void); // 获取 super_pos 结构 struct super_block_ops *alloc_super_block_ops(void); // 获取 inode 结构 struct inode *alloc_inode(void); // 获取 inode_ops 结构 struct inode_ops *alloc_inode_ops(void); // 获取 dentry 结构 struct dentry *alloc_dentry(void); // 获取 dentry_ops 结构 struct dentry_ops *alloc_dentry_ops(void); // 获取 file 结构 struct file *alloc_file(void); // 获取 file_ops 结构 struct file_ops *alloc_file_ops(void); // 释放 super_block 结构 void free_super_block(struct super_block *sb); // 释放 super_block_ops 结构 void free_super_block_ops(struct super_ops *sb_ops); // 释放 inode 结构 void free_inode(struct inode *inode); // 释放 inode_ops 结构 void free_inode_ops(struct inode_ops *inode_ops); // 释放 dentry 结构 void free_dentry(struct dentry *dentry); // 释放 dentry_ops 结构 void free_dentry_ops(struct dentry_ops *dentry_ops); // 释放 file 结构 void free_file(struct file *file); // 释放 file_ops 结构 void free_file_ops(struct file_ops *file_ops); // 打开文件 int vfs_open(const char *filename, uint32_t openflag); // 关闭文件 int vfs_close(int fd); // 读取文件 int vfs_read(int fd, char *buff, size_t size); // 写入文件 int vfs_write(int fd, const char *buff, size_t size); #endif // INCLUDE_FS_H_ ================================================ FILE: include/init.h ================================================ /* * ===================================================================================== * * Filename: init.h * * Description: 内核初始化 * * Version: 1.0 * Created: 2015年05月31日 13时15分20秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_INIT_H_ #define INCLUDE_INIT_H_ // 体系结构无关的内核初始化函数 void kern_init(void); #endif // INCLUDE_INIT_H_ ================================================ FILE: include/kio.h ================================================ /* * ===================================================================================== * * Filename: kio.h * * Description: 输入输出的实现 * * Version: 1.0 * Created: 2015年01月11日 17时15分20秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_KIO_H_ #define INCLUDE_KIO_H_ // 读取一个字符 char getchar(void); #endif // INCLUDE_KIO_H_ ================================================ FILE: include/lib/list.h ================================================ /* * ===================================================================================== * * Filename: list.h * * Description: 模仿 Linux 内核的 list.h * * Version: 1.0 * Created: 2014年11月08日 21时28分38秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_LIB_LIST_H_ #define INCLUDE_LIB_LIST_H_ #include #define list_entry(ptr,type,member) (type *)((char *)ptr - __offsetof(type,member)) #define __offsetof(TYPE, MEMBER) ((unsigned int) &((TYPE *)0)->MEMBER) #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } static inline void list_add_before(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } static inline void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); } static inline void list_replace(struct list_head *old, struct list_head *new) { new->next = old->next; new->next->prev = new; new->prev = old->prev; new->prev->next = new; } static inline void list_replace_init(struct list_head *old, struct list_head *new) { list_replace(old, new); INIT_LIST_HEAD(old); } static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } static inline void list_move(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add(list, head); } static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add_tail(list, head); } static inline int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; } static inline int list_empty(const struct list_head *head) { return head->next == head; } static inline int list_empty_careful(const struct list_head *head) { struct list_head *next = head->next; return (next == head) && (next == head->prev); } static inline int list_is_singular(const struct list_head *head) { return !list_empty(head) && (head->next == head->prev); } static inline void __list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry) { struct list_head *new_first = entry->next; list->next = head->next; list->next->prev = list; list->prev = entry; entry->next = list; head->next = new_first; new_first->prev = head; } static inline void list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry) { if (list_empty(head)) return; if (list_is_singular(head) && (head->next != entry && head != entry)) return; if (entry == head) INIT_LIST_HEAD(list); else __list_cut_position(list, head, entry); } static inline void __list_splice(const struct list_head *list, struct list_head *prev, struct list_head *next) { struct list_head *first = list->next; struct list_head *last = list->prev; first->prev = prev; prev->next = first; last->next = next; next->prev = last; } static inline void list_splice(const struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head, head->next); } static inline void list_splice_tail(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head->prev, head); } static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head, head->next); INIT_LIST_HEAD(list); } } static inline void list_splice_tail_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head->prev, head); INIT_LIST_HEAD(list); } } #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); pos = pos->prev) #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) #define list_for_each_prev_safe(pos, n, head) \ for (pos = (head)->prev, n = pos->prev; \ pos != (head); \ pos = n, n = pos->prev) #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member); \ pos->member != (head); \ pos = list_entry(pos->member.prev, typeof(*pos), member)) #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) #define list_for_each_entry_reverse_safe(pos, n, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.prev, typeof(*n), member)) #endif // INCLUDE_LIB_LIST_H_ ================================================ FILE: include/lib/rbtree.h ================================================ /* * ===================================================================================== * * Filename: rbtree.h * * Description: 红黑树的实现 * * Version: 1.0 * Created: 2014年11月12日 09时29分04秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_LIB_RBTREE_H_ #define INCLUDE_LIB_RBTREE_H_ /* Red Black Trees (C) 1999 Andrea Arcangeli 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 linux/include/linux/rbtree.h To use rbtrees you'll have to implement your own insert and search cores. This will avoid us to use callbacks and to drop drammatically performances. I know it's not the cleaner way, but in C (not in C++) to get performances and genericity... Some example of insert and search follows here. The search is a plain normal search over an ordered tree. The insert instead must be implemented in two steps: First, the code must insert the element in order as a red leaf in the tree, and then the support library function rb_insert_color() must be called. Such function will do the not trivial work to rebalance the rbtree, if necessary. ----------------------------------------------------------------------- static inline struct page * rb_search_page_cache(struct inode * inode, unsigned long offset) { struct rb_node * n = inode->i_rb_page_cache.rb_node; struct page * page; while (n) { page = rb_entry(n, struct page, rb_page_cache); if (offset < page->offset) n = n->rb_left; else if (offset > page->offset) n = n->rb_right; else return page; } return NULL; } static inline struct page * __rb_insert_page_cache(struct inode * inode, unsigned long offset, struct rb_node * node) { struct rb_node ** p = &inode->i_rb_page_cache.rb_node; struct rb_node * parent = NULL; struct page * page; while (*p) { parent = *p; page = rb_entry(parent, struct page, rb_page_cache); if (offset < page->offset) p = &(*p)->rb_left; else if (offset > page->offset) p = &(*p)->rb_right; else return page; } rb_link_node(node, parent, p); return NULL; } static inline struct page * rb_insert_page_cache(struct inode * inode, unsigned long offset, struct rb_node * node) { struct page * ret; if ((ret = __rb_insert_page_cache(inode, offset, node))) goto out; rb_insert_color(node, &inode->i_rb_page_cache); out: return ret; } ----------------------------------------------------------------------- */ #if defined(container_of) #undef container_of #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #else #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #endif #if defined(offsetof) #undef offsetof #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #else #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif #undef NULL #if defined(__cplusplus) #define NULL 0 #else #define NULL ((void *)0) #endif struct rb_node { unsigned long rb_parent_color; #define RB_RED 0 #define RB_BLACK 1 struct rb_node *rb_right; struct rb_node *rb_left; } __attribute__((aligned(sizeof(long)))); /* The alignment might seem pointless, but allegedly CRIS needs it */ struct rb_root { struct rb_node *rb_node; }; #define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) #define rb_color(r) ((r)->rb_parent_color & 1) #define rb_is_red(r) (!rb_color(r)) #define rb_is_black(r) rb_color(r) #define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) #define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) { rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p; } static inline void rb_set_color(struct rb_node *rb, int color) { rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; } #define RB_ROOT (struct rb_root) { NULL, } #define rb_entry(ptr, type, member) container_of(ptr, type, member) #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) #define RB_EMPTY_NODE(node) (rb_parent(node) == node) #define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) static inline void rb_init_node(struct rb_node *rb) { rb->rb_parent_color = 0; rb->rb_right = NULL; rb->rb_left = NULL; RB_CLEAR_NODE(rb); } extern void rb_insert_color(struct rb_node *, struct rb_root *); extern void rb_erase(struct rb_node *, struct rb_root *); typedef void (*rb_augment_f)(struct rb_node *node, void *data); extern void rb_augment_insert(struct rb_node *node, rb_augment_f func, void *data); extern struct rb_node *rb_augment_erase_begin(struct rb_node *node); extern void rb_augment_erase_end(struct rb_node *node, rb_augment_f func, void *data); /* Find logical next and previous nodes in a tree */ extern struct rb_node *rb_next(const struct rb_node *); extern struct rb_node *rb_prev(const struct rb_node *); extern struct rb_node *rb_first(const struct rb_root *); extern struct rb_node *rb_last(const struct rb_root *); /* Fast replacement of a single node without remove/rebalance/add/rebalance */ extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, struct rb_node ** rb_link) { node->rb_parent_color = (unsigned long )parent; node->rb_left = node->rb_right = NULL; *rb_link = node; } #endif // INCLUDE_LIB_RBTREE_H_ ================================================ FILE: include/lib/string.h ================================================ /* * ===================================================================================== * * Filename: string.h * * Description: 字符串相关函数 * * Version: 1.0 * Created: 2014年11月04日 11时02分12秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_LIB_STRING_H_ #define INCLUDE_LIB_STRING_H_ #include void memcpy(void *dest, void *src, uint32_t len); void memset(void *dest, uint8_t val, uint32_t len); void bzero(void *dest, uint32_t len); int strcmp(const char *str1, const char *str2); char *strcpy(char *dest, const char *src); char *strncpy(char *dest, const char *src, uint32_t len); char *strcat(char *dest, const char *src); int strlen(const char *src); #endif // INCLUDE_LIB_STRING_H_ ================================================ FILE: include/mboot.h ================================================ /* * ===================================================================================== * * Filename: mboot.h * * Description: Multiboot 结构的定义 * * Version: 1.0 * Created: 2014年11月04日 11时00分59秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_MULTIBOOT_H_ #define INCLUDE_MULTIBOOT_H_ #include /** * 启动后,在32位内核进入点,机器状态如下: * 1. CS 指向基地址为 0x00000000,限长为4G – 1的代码段描述符。 * 2. DS,SS,ES,FS 和 GS 指向基地址为0x00000000,限长为4G – 1的数据段描述符。 * 3. A20 地址线已经打开。 * 4. 页机制被禁止。 * 5. 中断被禁止。 * 6. EAX = 0x2BADB002 * 7. 系统信息和启动信息块的线性地址保存在 EBX中(相当于一个指针)。 * 以下即为这个信息块的结构 */ typedef struct multiboot_t { uint32_t flags; // Multiboot 的版本信息 /** * 从 BIOS 获知的可用内存 * * mem_lower和mem_upper分别指出了低端和高端内存的大小,单位是K。 * 低端内存的首地址是0,高端内存的首地址是1M。 * 低端内存的最大可能值是640K。 * 高端内存的最大可能值是最大值减去1M。但并不保证是这个值。 */ uint32_t mem_lower; uint32_t mem_upper; uint32_t boot_device; // 指出引导程序从哪个BIOS磁盘设备载入的OS映像 uint32_t cmdline; // 内核命令行 uint32_t mods_count; // boot 模块列表 uint32_t mods_addr; /** * ELF 格式内核映像的section头表。 * 包括每项的大小、一共有几项以及作为名字索引的字符串表。 */ uint32_t num; uint32_t size; uint32_t addr; uint32_t shndx; /** * 以下两项指出保存由BIOS提供的内存分布的缓冲区的地址和长度 * mmap_addr是缓冲区的地址,mmap_length是缓冲区的总大小 * 缓冲区由一个或者多个下面的大小/结构对 mmap_entry_t 组成 */ uint32_t mmap_length; uint32_t mmap_addr; uint32_t drives_length; // 指出第一个驱动器结构的物理地址 uint32_t drives_addr; // 指出第一个驱动器这个结构的大小 uint32_t config_table; // ROM 配置表 uint32_t boot_loader_name; // boot loader 的名字 uint32_t apm_table; // APM 表 uint32_t vbe_control_info; uint32_t vbe_mode_info; uint32_t vbe_mode; uint32_t vbe_interface_seg; uint32_t vbe_interface_off; uint32_t vbe_interface_len; } __attribute__((packed)) multiboot_t; /** * size是相关结构的大小,单位是字节,它可能大于最小值20 * base_addr_low是启动地址的低32位,base_addr_high是高32位,启动地址总共有64位 * length_low是内存区域大小的低32位,length_high是内存区域大小的高32位,总共是64位 * type是相应地址区间的类型,1代表可用RAM,所有其它的值代表保留区域 */ typedef struct mmap_entry_t { uint32_t size; // 留意 size 是不含 size 自身变量的大小 uint32_t base_addr_low; uint32_t base_addr_high; uint32_t length_low; uint32_t length_high; uint32_t type; } __attribute__((packed)) mmap_entry_t; // type是相应地址区间的类型,1代表可用RAM,所有其它的值代表保留区域 #define MULTIBOOT_TYPE_RAM 1 // 声明全局的 multiboot_t * 指针 // 内核未建立分页机制前暂存的指针 extern multiboot_t *mboot_ptr_tmp; // 内核页表建立后的指针 extern multiboot_t *glb_mboot_ptr; #endif // INCLUDE_MULTIBOOT_H_ ================================================ FILE: include/mbr.h ================================================ /* * ===================================================================================== * * Filename: mbr.h * * Description: MBR 信息定义 * * Version: 1.0 * Created: 2015年02月04日 10时40分13秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_MBR_H_ #define INCLUDE_MBR_H_ #include #include #define SECTION_SIZE 512 // 扇区大小 #define MBR_CODE_LENGTH 446 // MBR代码长度 #define PARTITION_SIZE 16 // 分区表项大小 #define PARTITION_COUNT 4 // 分区表项目个数 typedef struct partition_info_t { uint8_t active_flag; // 活动分区标记(0x0表示非活动,0x80表示活动) uint8_t start_chs[3]; // 起始磁头号+扇区号+柱面号。磁头号1字节;扇区号2字节低6位;柱面号2字节高2位+3字节 uint8_t partition_type; // 分区类型 uint8_t end_chs[3]; // 结束磁头号,含义同起始磁头号 uint32_t start_sector; // 逻辑起始扇区号 uint32_t nr_sectors; // 所占用扇区数 } __attribute__((packed)) partition_info_t; typedef struct mbr_info_t { uint8_t mbr_code[MBR_CODE_LENGTH]; // 主引导代码 partition_info_t part[PARTITION_COUNT]; // 4 个主分区表信息 uint16_t magic_num; // 魔数 0xAA55 } __attribute__((packed)) mbr_info_t; // MBR信息 extern mbr_info_t mbr_info; // 读取分区信息 int read_mbr_info(block_dev_t *bdev); // 输出分区信息 void show_partition_info(void); #endif // INCLUDE_MBR_H_ ================================================ FILE: include/mm/buddy_mm.h ================================================ /* * ===================================================================================== * * Filename: buddy_mm.h * * Description: 伙伴算法物理内存管理子系统 * * Version: 1.0 * Created: 2014年11月05日 11时36分16秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_MM_BUDDY_MM_H_ #define INCLUDE_MM_BUDDY_MM_H_ // 简单内存管理系统 extern struct pmm_manager buddy_mm_manager; #endif // INCLUDE_MM_BUDDY_MM_H_ ================================================ FILE: include/mm/ff_mm.h ================================================ /* * ===================================================================================== * * Filename: ff_mm.h * * Description: First-Fit 物理内存管理子系统 * * Version: 1.0 * Created: 2014年11月05日 11时36分16秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_MM_FF_MM_H_ #define INCLUDE_MM_FF_MM_H_ // 简单内存管理系统 extern struct pmm_manager ff_mm_manager; #endif // INCLUDE_MM_FF_MM_H_ ================================================ FILE: include/mm/mm.h ================================================ /* * ===================================================================================== * * Filename: mm.h * * Description: 内存管理的头文件 * * Version: 1.0 * Created: 2014年11月04日 13时31分10秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_MM_MM_H #define INCLUDE_MM_MM_H #include #include #include // 内存管理子系统初始化 void mm_init(void); #endif // INCLUDE_MM_MM_H ================================================ FILE: include/mm/slob.h ================================================ /* * ===================================================================================== * * Filename: slob.h * * Description: slob 内存分配器 * * Version: 1.0 * Created: 2014年11月11日 15时39分57秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_MM_SLOB_H_ #define INCLUDE_MM_SLOB_H_ #include // slob 分配器初始化 void slob_init(void); // 任意大小的内存分配函数 void *kmalloc(uint32_t size); // 任意大小的内存释放函数 void kfree(void *addr); #endif // INCLUDE_MM_SLOB_H_ ================================================ FILE: include/sched.h ================================================ /* * ===================================================================================== * * Filename: sched.h * * Description: 调度相关 * * Version: 1.0 * Created: 2014年11月04日 15时07分07秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_SCHEDULING_H_ #define INCLUDE_SCHEDULING_H_ #include #include // clock 中断回调函数 void clock_callback(pt_regs_t *regs); // 任务调度 void schedule(void); // 唤醒任务 void wakeup_task(struct task_struct *task); #endif // INCLUDE_SCHEDULING_H_ ================================================ FILE: include/sync.h ================================================ /* * ===================================================================================== * * Filename: sync.h * * Description: sync * * Version: 1.0 * Created: 2014年11月06日 16时56分50秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_SYNC_H_ #define INCLUDE_SYNC_H_ #include #include #include static inline bool __intr_store(void) { if (read_eflags() & FL_IF) { disable_intr(); return true; } return false; } static inline void __intr_restore(bool flag) { if (flag) { enable_intr(); } } #define local_intr_store(x) do { x = __intr_store(); } while (0) #define local_intr_restore(x) __intr_restore(x); #endif // INCLUDE_SYNC_H_ ================================================ FILE: include/types.h ================================================ /* * ===================================================================================== * * Filename: types.h * * Description: 一些类型的定义 * * Version: 1.0 * Created: 2014年11月04日 10时51分50秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_TYPES_H_ #define INCLUDE_TYPES_H_ #ifndef NULL #define NULL 0 #endif #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #define __UNUSED__ __attribute__((unused)) typedef enum bool { false = 0, true = 1 } bool; typedef unsigned long long uint64_t; typedef long long int64_t; typedef unsigned int uint32_t; typedef int int32_t; typedef unsigned short uint16_t; typedef short int16_t; typedef unsigned char uint8_t; typedef char int8_t; typedef unsigned int size_t; typedef int ssize_t; // 时间类型 typedef uint32_t time_t; // 进程 PID typedef int32_t pid_t; // 页目录数据类型 typedef uint32_t pgd_t; // 页表数据类型 typedef uint32_t pte_t; // 原子类型 typedef struct { volatile int counter; } atomic_t; // 内核链表类型 struct list_head { struct list_head *next, *prev; }; #endif // INCLUDE_TYPES_H_ ================================================ FILE: include/vargs.h ================================================ /* * ===================================================================================== * * Filename: vargs.h * * Description: 可变形参表相关宏 * * Version: 1.0 * Created: 2014年11月04日 11时44分02秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #ifndef INCLUDE_VARGS_H_ #define INCLUDE_VARGS_H_ typedef __builtin_va_list va_list; #define va_start(ap, last) (__builtin_va_start(ap, last)) #define va_arg(ap, type) (__builtin_va_arg(ap, type)) #define va_end(ap) #endif // INCLUDE_VARGS_H_ ================================================ FILE: init/kmain.c ================================================ /* * ===================================================================================== * * Filename: kmain.c * * Description: 内核初始化 * * Version: 1.0 * Created: 2014年11月04日 10时05分01秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #include #include #include #include static void kthread_test(void) __UNUSED__; // 内核初始化函数 void kern_init(void) { debug_init(); arch_init(); mm_init(); task_init(); fs_init(); enable_intr(); // kthread_test(); uint8_t ch = 0; while (true) { if ((ch = getchar()) != 0) { if (ch == 80) { console_view_down(1); } else if (ch == 72) { console_view_up(1); } } } while (true) { cpu_hlt(); } } static int init_main(void *args) { cprintk(rc_black, rc_red, "It's %s thread pid = %d args: %s\n\n", current->name, current->pid, (const char *)args); while (true) { cprintk(rc_black, rc_blue, "C"); uint32_t i = 100000; while (i--); } return 0; } static int user_mode_test_main(void *args) { cprintk(rc_black, rc_blue, "It's %s thread pid = %d args: %s\n", current->name, current->pid, (const char *)args); cprintk(rc_black, rc_light_brown, "\nTest syscall now:\n"); __asm__ volatile ("mov $0, %eax"); __asm__ volatile ("int $0x80"); printk("\n"); while (true) { cprintk(rc_black, rc_green, "A"); uint32_t i = 100000; while (i--); } return 0; } static void kthread_test(void) { pid_t pid; pid = kernel_thread(user_mode_test_main, "ring0 -> ring3", 0); assert(pid > 0, "user_mode_test thread error!"); glb_init_task = find_task(pid); set_proc_name(glb_init_task, "user_mode_test"); cprintk(rc_black, rc_green, "\nIt's %s thread pid = %d\n\n", current->name, current->pid); pid = kernel_thread(init_main, "I'm a new thread", 0); assert(pid > 0, "init_task error!"); glb_init_task = find_task(pid); set_proc_name(glb_init_task, "init"); while (true) { cprintk(rc_black, rc_red, "B"); uint32_t i = 100000; while (i--); } } ================================================ FILE: isodir/boot/grub/grub.cfg ================================================ menuentry "hurlex" { multiboot /boot/hx_kernel } ================================================ FILE: kernel/errno.c ================================================ /* * ===================================================================================== * * Filename: errno.c * * Description: 错误处理相关 * * Version: 1.0 * Created: 2015年01月11日 16时33分12秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include // 内核错误的字符串定义 static const char * const error_string[MAXERROR + 1] = { [0] NULL, [E_UNSPECIFIED] "unspecified error", [E_BAD_PROC] "bad process", [E_INVAL] "invalid parameter", [E_NO_MEM] "out of memory", [E_NO_FREE_PROC] "out of processes", [E_FAULT] "segmentation fault", }; // 获得错误号对应的字符串 const char *strerr(int errno) { if (errno < MAXERROR) { return error_string[errno]; } return (const char *)("unknown error"); } ================================================ FILE: kernel/kio.c ================================================ /* * ===================================================================================== * * Filename: kio.c * * Description: 输入输出的实现 * * Version: 1.0 * Created: 2015年02月08日 12时07分31秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include // 读取一个字符 char getchar(void) { char ch; char_dev_t *kb_dev = &kboard_dev; if (!kb_dev->ops.device_valid()) { return 0; } while (kb_dev->ops.read(&ch, 1) == 0) { cpu_hlt(); } return ch; } ================================================ FILE: kernel/printk.c ================================================ /* * ===================================================================================== * * Filename: printk.c * * Description: 内核屏幕输出函数 * * Version: 1.0 * Created: 2014年11月04日 10时57分13秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include static int vsprintf(char *buff, const char *format, va_list args); void printk(const char *format, ...) { // 避免频繁创建临时变量,内核的栈很宝贵 static char buff[10240]; va_list args; int i; va_start(args, format); i = vsprintf(buff, format, args); va_end(args); buff[i] = '\0'; console_write(buff); } void cprintk(real_color_t back, real_color_t fore, const char *format, ...) { // 避免频繁创建临时变量,内核的栈很宝贵 static char buff[10240]; va_list args; int i; va_start(args, format); i = vsprintf(buff, format, args); va_end(args); buff[i] = '\0'; console_write_color(buff, back, fore); } #define is_digit(c) ((c) >= '0' && (c) <= '9') static int skip_atoi(const char **s) { int i = 0; while (is_digit(**s)) { i = i * 10 + *((*s)++) - '0'; } return i; } #define ZEROPAD 1 // pad with zero #define SIGN 2 // unsigned/signed long #define PLUS 4 // show plus #define SPACE 8 // space if plus #define LEFT 16 // left justified #define SPECIAL 32 // 0x #define SMALL 64 // use 'abcdef' instead of 'ABCDEF' #define do_div(n,base) ({ \ int __res; \ __asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ __res; }) static char *number(char *str, int num, int base, int size, int precision, int type) { char c, sign, tmp[36]; const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int i; if (type & SMALL) { digits ="0123456789abcdefghijklmnopqrstuvwxyz"; } if (type & LEFT) { type &= ~ZEROPAD; } if (base < 2 || base > 36) { return 0; } c = (type & ZEROPAD) ? '0' : ' ' ; if (type & SIGN && num < 0) { sign = '-'; num = -num; } else { sign = (type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); } if (sign) { size--; } if (type & SPECIAL) { if (base == 16) { size -= 2; } else if (base == 8) { size--; } } i = 0; if (num == 0) { tmp[i++] = '0'; } else { while (num != 0) { tmp[i++] = digits[do_div(num,base)]; } } if (i > precision) { precision = i; } size -= precision; if (!(type&(ZEROPAD+LEFT))) { while (size-- > 0) { *str++ = ' '; } } if (sign) { *str++ = sign; } if (type & SPECIAL) { if (base == 8) { *str++ = '0'; } else if (base == 16) { *str++ = '0'; *str++ = digits[33]; } } if (!(type&LEFT)) { while (size-- > 0) { *str++ = c; } } while (i < precision--) { *str++ = '0'; } while (i-- > 0) { *str++ = tmp[i]; } while (size-- > 0) { *str++ = ' '; } return str; } static int vsprintf(char *buff, const char *format, va_list args) { int len; int i; char *str; char *s; int *ip; int flags; // flags to number() int field_width; // width of output field int precision; // min. # of digits for integers; max number of chars for from string for (str = buff ; *format ; ++format) { if (*format != '%') { *str++ = *format; continue; } flags = 0; repeat: ++format; // this also skips first '%' switch (*format) { case '-': flags |= LEFT; goto repeat; case '+': flags |= PLUS; goto repeat; case ' ': flags |= SPACE; goto repeat; case '#': flags |= SPECIAL; goto repeat; case '0': flags |= ZEROPAD; goto repeat; } // get field width field_width = -1; if (is_digit(*format)) { field_width = skip_atoi(&format); } else if (*format == '*') { // it's the next argument field_width = va_arg(args, int); if (field_width < 0) { field_width = -field_width; flags |= LEFT; } } // get the precision precision = -1; if (*format == '.') { ++format; if (is_digit(*format)) { precision = skip_atoi(&format); } else if (*format == '*') { // it's the next argument precision = va_arg(args, int); } if (precision < 0) { precision = 0; } } // get the conversion qualifier //int qualifier = -1; // 'h', 'l', or 'L' for integer fields if (*format == 'h' || *format == 'l' || *format == 'L') { //qualifier = *format; ++format; } switch (*format) { case 'c': if (!(flags & LEFT)) { while (--field_width > 0) { *str++ = ' '; } } *str++ = (unsigned char) va_arg(args, int); while (--field_width > 0) { *str++ = ' '; } break; case 's': s = va_arg(args, char *); len = strlen(s); if (precision < 0) { precision = len; } else if (len > precision) { len = precision; } if (!(flags & LEFT)) { while (len < field_width--) { *str++ = ' '; } } for (i = 0; i < len; ++i) { *str++ = *s++; } while (len < field_width--) { *str++ = ' '; } break; case 'o': str = number(str, va_arg(args, unsigned long), 8, field_width, precision, flags); break; case 'p': if (field_width == -1) { field_width = 8; flags |= ZEROPAD; } str = number(str, (unsigned long) va_arg(args, void *), 16, field_width, precision, flags); break; case 'x': flags |= SMALL; case 'X': str = number(str, va_arg(args, unsigned long), 16, field_width, precision, flags); break; case 'd': case 'i': flags |= SIGN; case 'u': str = number(str, va_arg(args, unsigned long), 10, field_width, precision, flags); break; case 'b': str = number(str, va_arg(args, unsigned long), 2, field_width, precision, flags); break; case 'n': ip = va_arg(args, int *); *ip = (str - buff); break; default: if (*format != '%') *str++ = '%'; if (*format) { *str++ = *format; } else { --format; } break; } } *str = '\0'; return (str -buff); } ================================================ FILE: kernel/sched/sched.c ================================================ /* * ===================================================================================== * * Filename: sched.c * * Description: 调度程序 * * Version: 1.0 * Created: 2014年11月04日 15时06分04秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include "sched.h" void clock_callback(__UNUSED__ pt_regs_t *regs) { schedule(); } void schedule(void) { struct task_struct *task_next = NULL; struct list_head *le = NULL, *last = NULL; bool intr_flag = false; local_intr_store(intr_flag); { current->need_resched = false; // 如果当前是内核调度线程在执行,就从任务链起始开始,否则从当前任务开始 le = last = (current == glb_idle_task) ? &task_list : &(current->list); for (le = le->next; le != last; le = le->next) { if (le != &task_list) { task_next = le_to_task(le); if (task_next->state == TASK_RUNNABLE) { break; } } } // 未找到可运行的任务 if (!task_next || task_next->state != TASK_RUNNABLE) { task_next = glb_idle_task; } // 时间片递增 task_next->runs_time++; if (task_next != current) { task_run(task_next); } } local_intr_restore(intr_flag); } void wakeup_task(struct task_struct *task) { if (task->state != TASK_ZOMBIE) { task->state = TASK_RUNNABLE; } } ================================================ FILE: lib/rbtree.c ================================================ /* * ===================================================================================== * * Filename: rbtree.c * * Description: 红黑树的实现 * * Version: 1.0 * Created: 2014年11月12日 09时33分36秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) { struct rb_node *right = node->rb_right; struct rb_node *parent = rb_parent(node); if ((node->rb_right = right->rb_left)) rb_set_parent(right->rb_left, node); right->rb_left = node; rb_set_parent(right, parent); if (parent) { if (node == parent->rb_left) parent->rb_left = right; else parent->rb_right = right; } else { root->rb_node = right; } rb_set_parent(node, right); } static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) { struct rb_node *left = node->rb_left; struct rb_node *parent = rb_parent(node); if ((node->rb_left = left->rb_right)) rb_set_parent(left->rb_right, node); left->rb_right = node; rb_set_parent(left, parent); if (parent) { if (node == parent->rb_right) parent->rb_right = left; else parent->rb_left = left; } else { root->rb_node = left; } rb_set_parent(node, left); } void rb_insert_color(struct rb_node *node, struct rb_root *root) { struct rb_node *parent, *gparent; while ((parent = rb_parent(node)) && rb_is_red(parent)) { gparent = rb_parent(parent); if (parent == gparent->rb_left) { { register struct rb_node *uncle = gparent->rb_right; if (uncle && rb_is_red(uncle)) { rb_set_black(uncle); rb_set_black(parent); rb_set_red(gparent); node = gparent; continue; } } if (parent->rb_right == node) { register struct rb_node *tmp; __rb_rotate_left(parent, root); tmp = parent; parent = node; node = tmp; } rb_set_black(parent); rb_set_red(gparent); __rb_rotate_right(gparent, root); } else { { register struct rb_node *uncle = gparent->rb_left; if (uncle && rb_is_red(uncle)) { rb_set_black(uncle); rb_set_black(parent); rb_set_red(gparent); node = gparent; continue; } } if (parent->rb_left == node) { register struct rb_node *tmp; __rb_rotate_right(parent, root); tmp = parent; parent = node; node = tmp; } rb_set_black(parent); rb_set_red(gparent); __rb_rotate_left(gparent, root); } } rb_set_black(root->rb_node); } static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, struct rb_root *root) { struct rb_node *other; while ((!node || rb_is_black(node)) && node != root->rb_node) { if (parent->rb_left == node) { other = parent->rb_right; if (rb_is_red(other)) { rb_set_black(other); rb_set_red(parent); __rb_rotate_left(parent, root); other = parent->rb_right; } if ((!other->rb_left || rb_is_black(other->rb_left)) && (!other->rb_right || rb_is_black(other->rb_right))) { rb_set_red(other); node = parent; parent = rb_parent(node); } else { if (!other->rb_right || rb_is_black(other->rb_right)) { rb_set_black(other->rb_left); rb_set_red(other); __rb_rotate_right(other, root); other = parent->rb_right; } rb_set_color(other, rb_color(parent)); rb_set_black(parent); rb_set_black(other->rb_right); __rb_rotate_left(parent, root); node = root->rb_node; break; } } else { other = parent->rb_left; if (rb_is_red(other)) { rb_set_black(other); rb_set_red(parent); __rb_rotate_right(parent, root); other = parent->rb_left; } if ((!other->rb_left || rb_is_black(other->rb_left)) && (!other->rb_right || rb_is_black(other->rb_right))) { rb_set_red(other); node = parent; parent = rb_parent(node); } else { if (!other->rb_left || rb_is_black(other->rb_left)) { rb_set_black(other->rb_right); rb_set_red(other); __rb_rotate_left(other, root); other = parent->rb_left; } rb_set_color(other, rb_color(parent)); rb_set_black(parent); rb_set_black(other->rb_left); __rb_rotate_right(parent, root); node = root->rb_node; break; } } } if (node) rb_set_black(node); } void rb_erase(struct rb_node *node, struct rb_root *root) { struct rb_node *child, *parent; int color; if (!node->rb_left) { child = node->rb_right; } else if (!node->rb_right) { child = node->rb_left; } else { struct rb_node *old = node, *left; node = node->rb_right; while ((left = node->rb_left) != NULL) node = left; if (rb_parent(old)) { if (rb_parent(old)->rb_left == old) rb_parent(old)->rb_left = node; else rb_parent(old)->rb_right = node; } else root->rb_node = node; child = node->rb_right; parent = rb_parent(node); color = rb_color(node); if (parent == old) { parent = node; } else { if (child) rb_set_parent(child, parent); parent->rb_left = child; node->rb_right = old->rb_right; rb_set_parent(old->rb_right, node); } node->rb_parent_color = old->rb_parent_color; node->rb_left = old->rb_left; rb_set_parent(old->rb_left, node); goto color; } parent = rb_parent(node); color = rb_color(node); if (child) rb_set_parent(child, parent); if (parent) { if (parent->rb_left == node) parent->rb_left = child; else parent->rb_right = child; } else { root->rb_node = child; } color: if (color == RB_BLACK) __rb_erase_color(child, parent, root); } static void rb_augment_path(struct rb_node *node, rb_augment_f func, void *data) { struct rb_node *parent; up: func(node, data); parent = rb_parent(node); if (!parent) return; if (node == parent->rb_left && parent->rb_right) func(parent->rb_right, data); else if (parent->rb_left) func(parent->rb_left, data); node = parent; goto up; } /* * after inserting @node into the tree, update the tree to account for * both the new entry and any damage done by rebalance */ void rb_augment_insert(struct rb_node *node, rb_augment_f func, void *data) { if (node->rb_left) node = node->rb_left; else if (node->rb_right) node = node->rb_right; rb_augment_path(node, func, data); } /* * before removing the node, find the deepest node on the rebalance path * that will still be there after @node gets removed */ struct rb_node *rb_augment_erase_begin(struct rb_node *node) { struct rb_node *deepest; if (!node->rb_right && !node->rb_left) deepest = rb_parent(node); else if (!node->rb_right) deepest = node->rb_left; else if (!node->rb_left) deepest = node->rb_right; else { deepest = rb_next(node); if (deepest->rb_right) deepest = deepest->rb_right; else if (rb_parent(deepest) != node) deepest = rb_parent(deepest); } return deepest; } /* * after removal, update the tree to account for the removed entry * and any rebalance damage. */ void rb_augment_erase_end(struct rb_node *node, rb_augment_f func, void *data) { if (node) rb_augment_path(node, func, data); } /* * This function returns the first node (in sort order) of the tree. */ struct rb_node *rb_first(const struct rb_root *root) { struct rb_node *n; n = root->rb_node; if (!n) return NULL; while (n->rb_left) n = n->rb_left; return n; } struct rb_node *rb_last(const struct rb_root *root) { struct rb_node *n; n = root->rb_node; if (!n) return NULL; while (n->rb_right) n = n->rb_right; return n; } struct rb_node *rb_next(const struct rb_node *node) { struct rb_node *parent; if (rb_parent(node) == node) return NULL; /* If we have a right-hand child, go down and then left as far as we can. */ if (node->rb_right) { node = node->rb_right; while (node->rb_left) node=node->rb_left; return (struct rb_node *)node; } /* No right-hand children. Everything down and left is smaller than us, so any 'next' node must be in the general direction of our parent. Go up the tree; any time the ancestor is a right-hand child of its parent, keep going up. First time it's a left-hand child of its parent, said parent is our 'next' node. */ while ((parent = rb_parent(node)) && node == parent->rb_right) node = parent; return parent; } struct rb_node *rb_prev(const struct rb_node *node) { struct rb_node *parent; if (rb_parent(node) == node) return NULL; /* If we have a left-hand child, go down and then right as far as we can. */ if (node->rb_left) { node = node->rb_left; while (node->rb_right) node=node->rb_right; return (struct rb_node *)node; } /* No left-hand children. Go up till we find an ancestor which is a right-hand child of its parent */ while ((parent = rb_parent(node)) && node == parent->rb_left) node = parent; return parent; } void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root) { struct rb_node *parent = rb_parent(victim); /* Set the surrounding nodes to point to the replacement */ if (parent) { if (victim == parent->rb_left) parent->rb_left = new; else parent->rb_right = new; } else { root->rb_node = new; } if (victim->rb_left) rb_set_parent(victim->rb_left, new); if (victim->rb_right) rb_set_parent(victim->rb_right, new); /* Copy the pointers/colour from the victim to the replacement */ *new = *victim; } ================================================ FILE: lib/string.c ================================================ /* * ===================================================================================== * * Filename: string.c * * Description: 字符串处理函数 * * Version: 1.0 * Created: 2014年11月04日 11时07分26秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include inline void memcpy(void *dest, void *src, uint32_t len) { uint8_t *sr = src; uint8_t *dst = dest; while (len != 0) { *dst++ = *sr++; len--; } } inline void memset(void *dest, uint8_t val, uint32_t len) { for (uint8_t *dst = (uint8_t *)dest; len != 0; len--) { *dst++ = val; } } inline void bzero(void *dest, uint32_t len) { memset(dest, 0, len); } inline int strcmp(const char *dest, const char *src) { int ret = 0 ; while(!(ret = *(unsigned char *)src - *(unsigned char *)dest) && *dest) { ++src; ++dest; } if (ret < 0) { ret = -1; } else if (ret > 0) { ret = 1; } return ret; } inline char *strcpy(char *dest, const char *src) { char *tmp = dest; while (*src) { *dest++ = *src++; } *dest = '\0'; return tmp; } char *strncpy(char *dest, const char *src, uint32_t len) { char *dst = dest; while (len > 0) { while (*src) { *dest++ = *src++; } len--; } *dest = '\0'; return dst; } inline char *strcat(char *dest, const char *src) { char *cp = dest; while (*cp) { cp++; } while ((*cp++ = *src++)) ; return dest; } inline int strlen(const char *src) { const char *eos = src; while (*eos++) ; return (eos - src - 1); } ================================================ FILE: mm/buddy_mm.c ================================================ /* * ===================================================================================== * * Filename: buddy_mm.c * * Description: 伙伴算法算法内存管理 * * Version: 1.0 * Created: 2014年11月05日 10时47分35秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #include // 简化 list_entry 使用 #define le_to_page(le) list_entry(le, page_t, list) // 每个独立的内存管理算法必须实现的4个接口函数 static void buddy_page_init(page_t *pages, uint32_t n); static uint32_t buddy_alloc_pages(uint32_t n); static void buddy_free_pages(uint32_t addr, uint32_t n); static uint32_t buddy_free_pages_count(void); // 管理结构 struct pmm_manager buddy_mm_manager = { "Buddy_Memory_Managentment", &buddy_page_init, &buddy_alloc_pages, &buddy_free_pages, &buddy_free_pages_count }; // 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 // 2^0 ~ 2^10 #define MAX_ORDER 10 // 内存管理结构 struct buddy_mm_struct { struct list_head free_list[MAX_ORDER + 1]; // 空闲内存块链 atomic_t nr_free[MAX_ORDER + 1]; // 对应链上内存块数量 page_t *pages_base; // 物理页管理结构起始地址 uint32_t mm_addr_start; // 物理内存页管理起始地址 uint32_t mm_addr_end; // 物理内存页管理结束地址 atomic_t phy_page_count; // 物理内存页的总数量 atomic_t phy_page_now_count; // 物理内存页的当前数量 }; static struct buddy_mm_struct buddy_mm_info; // x from 0 ~ MAX_ORDER #define free_list(x) (buddy_mm_info.free_list[x]) #define nr_free(x) (buddy_mm_info.nr_free[x]) static void buddy_show_memory_info(void); static void buddy_show_management_info(void) __UNUSED__; static void buddy_test_mm(void) __UNUSED__; static void buddy_page_init(page_t *pages, uint32_t n) { atomic_set(&buddy_mm_info.phy_page_count, n); atomic_set(&buddy_mm_info.phy_page_now_count, n); buddy_mm_info.pages_base = pages; buddy_mm_info.mm_addr_start = page_to_addr(&pages[0]); buddy_mm_info.mm_addr_end = page_to_addr(&pages[n-1]) + PMM_PAGE_SIZE; for (int i = 0; i <= MAX_ORDER; ++i) { INIT_LIST_HEAD(&free_list(i)); atomic_set(&nr_free(i), 0); } uint32_t order = MAX_ORDER; uint32_t order_size = (1u << order); page_t *p = pages; while (n != 0) { while (n >= order_size) { set_page_order_flag(p); p->order = order; list_add(&p->list, &free_list(order)); n -= order_size; p += order_size; atomic_inc(&nr_free(order)); } order--; order_size >>= 1; } buddy_show_memory_info(); buddy_show_management_info(); buddy_test_mm(); } static uint32_t get_order(uint32_t size) { uint32_t order = 0, order_size = 1; while (order <= MAX_ORDER) { if (order_size >= size) { return order; } order++; order_size <<= 1; } panic("getorder failed."); return 0; } static page_t *buddy_alloc_pages_sub(uint32_t order) { assert(order <= MAX_ORDER, "buddy_alloc_pages_sub cannot alloc over 1024 pages"); for (uint32_t cur_order = order; cur_order <= MAX_ORDER; ++cur_order) { if (!list_empty(&free_list(cur_order))) { struct list_head *le = (&(free_list(cur_order)))->next; page_t *page = le_to_page(le); atomic_dec(&nr_free(cur_order)); list_del(le); uint32_t size = 1u << cur_order; while (cur_order > order) { cur_order--; size >>= 1; page_t *buddy = page + size; buddy->order = cur_order; set_page_order_flag(buddy); atomic_inc(&nr_free(cur_order)); list_add(&buddy->list, &free_list(cur_order)); } clear_page_order_flag(page); return page; } } return 0; } static uint32_t buddy_alloc_pages(uint32_t n) { if (n <= 0 || n > (uint32_t)atomic_read(&buddy_mm_info.phy_page_now_count)) { return 0; } uint32_t order = get_order(n); uint32_t order_size = (1u << order); page_t *page = buddy_alloc_pages_sub(order); if (!page) { return 0; } if (n != order_size) { buddy_free_pages(page_to_addr(page + n), order_size -n); } atomic_sub(&buddy_mm_info.phy_page_now_count, n); return page_to_addr(page); } static inline uint32_t page_to_idx(page_t *page) { return (page - buddy_mm_info.pages_base); } static inline page_t *idx_to_page(uint32_t idx) { return (buddy_mm_info.pages_base + idx); } static bool page_is_buddy(page_t *page, uint32_t order) { if (page_to_idx(page) < (uint32_t)atomic_read(&buddy_mm_info.phy_page_count)) { return (is_page_order(page) && page->order == order); } return false; } static void buddy_free_pages_sub(page_t *base, uint32_t order) { uint32_t buddy_idx, page_idx = page_to_idx(base); for (page_t *p = base; p != base + (1u << order); ++p) { set_page_ref(p, 0); } while (order < MAX_ORDER) { buddy_idx = page_idx ^ (1u << order); page_t *buddy = idx_to_page(buddy_idx); if (!page_is_buddy(buddy, order)) { break; } atomic_dec(&nr_free(order)); list_del(&buddy->list); clear_page_order_flag(buddy); page_idx &= buddy_idx; order++; } page_t *page = idx_to_page(page_idx); page->order = order; set_page_order_flag(page); atomic_inc(&nr_free(order)); list_add(&page->list, &free_list(order)); } static void buddy_free_pages(uint32_t addr, uint32_t n) { if (n <= 0) { return; } page_t *base = addr_to_page(addr); atomic_add(&buddy_mm_info.phy_page_now_count, n); uint32_t order = 0, order_size = 1; while (n >= order_size) { if ((n & order_size) != 0) { buddy_free_pages_sub(base, order); base += order_size; n -= order_size; } order++; order_size <<= 1; } } static uint32_t buddy_free_pages_count(void) { return atomic_read(&buddy_mm_info.phy_page_now_count); } static void buddy_show_memory_info(void) { printk("Physical Memory Pages Start: %08X End: %08X\n\n", buddy_mm_info.mm_addr_start, buddy_mm_info.mm_addr_end); printk("Physical Memory Pages Total: %d Pages = %d KB\n\n", atomic_read(&buddy_mm_info.phy_page_count), atomic_read(&buddy_mm_info.phy_page_count) * 4); } static void buddy_show_management_info(void) { cprintk(rc_black, rc_green,"Buddy Memory Info:\n\n"); uint32_t count = 0; for (uint32_t order = 0; order < MAX_ORDER + 1; ++order) { count += atomic_read(&nr_free(order)) * (1u << order); cprintk(rc_black, rc_green, " order %2u (size: %4u * 4K) count: %3d\n", order, 1u << order, atomic_read(&nr_free(order))); } cprintk(rc_black, rc_green, "\n Buddy All Pages Count: %u\n\n", count); printk("Physical Memory Pages Used: %d Pages = %d KB\n\n", atomic_read(&buddy_mm_info.phy_page_count) - atomic_read(&buddy_mm_info.phy_page_now_count), (atomic_read(&buddy_mm_info.phy_page_count) - atomic_read(&buddy_mm_info.phy_page_now_count)) * 4); } static void buddy_test_mm(void) { cprintk(rc_black, rc_green, "\n%s Test Now:\n\n", buddy_mm_manager.name); cprintk(rc_black, rc_red, "before test:\n\n order 0~10 counts: "); for (uint32_t order = 0; order < MAX_ORDER + 1; ++order) { cprintk(rc_black, rc_red, "%3u ", atomic_read(&nr_free(order))); } printk("\n\n"); uint32_t page[10]; page[1] = buddy_alloc_pages(1); page[2] = buddy_alloc_pages(2); buddy_free_pages(page[1], 1); buddy_free_pages(page[2], 2); page[3] = buddy_alloc_pages(8); page[4] = buddy_alloc_pages(16); page[5] = buddy_alloc_pages(18); page[6] = buddy_alloc_pages(27); page[7] = buddy_alloc_pages(32); page[8] = buddy_alloc_pages(129); page[9] = buddy_alloc_pages(547); buddy_free_pages(page[3], 8); buddy_free_pages(page[4], 16); buddy_free_pages(page[5], 18); buddy_free_pages(page[6], 27); buddy_free_pages(page[7], 32); buddy_free_pages(page[8], 129); buddy_free_pages(page[9], 547); cprintk(rc_black, rc_red, "after test:\n\n order 0~10 counts: "); for (uint32_t order = 0; order < MAX_ORDER + 1; ++order) { cprintk(rc_black, rc_red, "%3u ", atomic_read(&nr_free(order))); } printk("\n\n"); } ================================================ FILE: mm/ff_mm.c ================================================ /* * ===================================================================================== * * Filename: ff_mm.c * * Description: First-Fit 算法内存管理 * * Version: 1.0 * Created: 2014年11月05日 10时47分35秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include #include #include // 简化 list_entry 使用 #define le_to_page(le) list_entry(le, page_t, list) // 每个独立的内存管理算法必须实现的4个接口函数 static void ff_page_init(page_t *pages, uint32_t n); static uint32_t ff_alloc_pages(uint32_t n); static void ff_free_pages(uint32_t addr, uint32_t n); static uint32_t ff_free_pages_count(void); // 管理结构 struct pmm_manager ff_mm_manager = { "First_Fit_Memory_Managentment", &ff_page_init, &ff_alloc_pages, &ff_free_pages, &ff_free_pages_count }; // 内存管理结构 struct ff_mm_struct { struct list_head free_list; // 空闲内存块链 uint32_t mm_addr_start; // 物理内存页管理起始地址 uint32_t mm_addr_end; // 物理内存页管理结束地址 atomic_t phy_page_count; // 物理内存页的总数量 atomic_t phy_page_now_count; // 物理内存页的当前数量 }; static struct ff_mm_struct ff_mm_info; static void ff_show_memory_info(void); static void ff_show_management_info(void); static void ff_test_mm(void) __UNUSED__; static void ff_page_init(page_t *pages, uint32_t n) { atomic_set(&ff_mm_info.phy_page_count, n); atomic_set(&ff_mm_info.phy_page_now_count, n); ff_mm_info.mm_addr_start = page_to_addr(&pages[0]); ff_mm_info.mm_addr_end = page_to_addr(&pages[n-1]) + PMM_PAGE_SIZE; INIT_LIST_HEAD(&ff_mm_info.free_list); for (page_t *p = pages; p < pages + n; ++p) { set_page_reserved_flag(p); list_add_before(&p->list, &ff_mm_info.free_list); } pages[0].ncount = n; set_page_ncount_flag(&pages[0]); ff_show_memory_info(); //ff_test_mm(); } static uint32_t ff_alloc_pages(uint32_t n) { if (n <= 0 || n > (uint32_t)atomic_read(&ff_mm_info.phy_page_now_count)) { return 0; } struct list_head *le, *len; le = &ff_mm_info.free_list; while ((le = le->next) != &ff_mm_info.free_list) { page_t *p = le_to_page(le); // 当前链之后的空闲内存页数满足需求 if (is_page_ncount(p) && p->ncount >= n) { for (uint32_t i = 0; i < n; ++i) { len = le->next; page_t *pp = le_to_page(le); clear_page_reserved_flag(pp); list_del(le); le = len; } } // 切割当前链后重新计算剩余值 if (p->ncount > n) { set_page_ncount_flag(le_to_page(le)); (le_to_page(le))->ncount = p->ncount - n; } p->ncount = 0; clear_page_ncount_flag(p); atomic_sub(&ff_mm_info.phy_page_now_count, n); return page_to_addr(p); } // 找不到满足请求的连续的物理内存块 return 0; } static void ff_free_pages(uint32_t addr, uint32_t n) { if (n <= 0) { return; } page_t *base = addr_to_page(addr); assert(!is_page_reserved(base), "ff_free_pages error!"); set_page_ref(base, 0); set_page_ncount_flag(base); base->ncount = n; // 找到插入点 page_t *p; struct list_head *le = &ff_mm_info.free_list; while ((le = le->next) != &ff_mm_info.free_list) { p = le_to_page(le); if (p > base) { break; } } // 插入所有释放的连续节点到 le 节点之前 // 即使 le 此时回到头节点也依旧正确 for (p = base; p < base + n; ++p) { list_add_before(&p->list, le); } // 如果 base 与之后的内存连续,则合并 p = le_to_page(le); if (base + n == p) { base->ncount += p->ncount; clear_page_ncount_flag(p); p->ncount = 0; } // 如果 base 与之前的内存连续,则合并 le = base->list.prev; p = le_to_page(le); if (le != &ff_mm_info.free_list && p == base - 1) { while (le != &ff_mm_info.free_list) { if (is_page_ncount(p)) { p->ncount += base->ncount; clear_page_ncount_flag(base); base->ncount = 0; } le = le->prev; p = le_to_page(le); } } atomic_add(&ff_mm_info.phy_page_now_count, n); } static uint32_t ff_free_pages_count(void) { return atomic_read(&ff_mm_info.phy_page_now_count); } static void ff_show_memory_info(void) { printk("Physical Memory Pages Start: %08X End: %08X\n\n", ff_mm_info.mm_addr_start, ff_mm_info.mm_addr_end); printk("Physical Memory Pages Total: %d Pages = %d KB\n\n", atomic_read(&ff_mm_info.phy_page_count), atomic_read(&ff_mm_info.phy_page_count) * 4); } static void ff_show_management_info(void) { printk("Physical Memory Pages Used: %d Pages = %d KB\n\n", atomic_read(&ff_mm_info.phy_page_count) - atomic_read(&ff_mm_info.phy_page_now_count), (atomic_read(&ff_mm_info.phy_page_count) - atomic_read(&ff_mm_info.phy_page_now_count)) * 4); } static void ff_test_mm(void) { printk("\n%s Test Now:\n\n", ff_mm_manager.name); uint32_t page1 = ff_alloc_pages(1); printk("Alloc Page 1 In: %08X\n", page1); ff_show_management_info(); uint32_t page2 = ff_alloc_pages(2); printk("Alloc Page 2 In: %08X\n", page2); ff_show_management_info(); printk("Free Page 1 In: %08X\n", page1); ff_free_pages(page1, 1); ff_show_management_info(); printk("Free Page 2 In: %08X\n", page2); ff_free_pages(page2, 2); ff_show_management_info(); uint32_t page3 = ff_alloc_pages(10); printk("Alloc Page 10 In: %08X\n", page3); ff_show_management_info(); printk("Free Page 10 In: %08X\n", page3); ff_free_pages(page3, 10); ff_show_management_info(); } ================================================ FILE: mm/mm.c ================================================ /* * ===================================================================================== * * Filename: mm.c * * Description: 内存管理子系统 * * Version: 1.0 * Created: 2014年11月05日 09时54分05秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include void mm_init(void) { pmm_init(); vmm_init(); slob_init(); } ================================================ FILE: mm/slob.c ================================================ /* * ===================================================================================== * * Filename: slob.c * * Description: slob 内存分配器 * * Version: 1.0 * Created: 2014年11月11日 15时15分41秒 * Revision: none * Compiler: gcc * * Author: Qianyi.lh (liuhuan), qianyi.lh@alibaba-inc.com * Company: Alibaba-Inc Aliyun * * ===================================================================================== */ #include #include #include typedef struct slob_block { uint32_t allocated : 1; // 该内存块是否已经被申请 uint32_t length : 31; // 当前内存块的长度 struct list_head list; } slob_block_t; #define SLOB_USED 1 #define SLOB_FREE 0 // slob 管理的内存数量 #define SLOB_PAGE_COUNT 1024 // slob 最小的内存分片限制 #define SLOB_MIN_PART 0x20 // 初始化头结点 LIST_HEAD(slob_head); // 简化 list_entry 使用 #define le_to_block(le) list_entry(le, slob_block_t, list) static void *__slob_alloc_pages(uint32_t size) { uint32_t addr = alloc_pages(size); if (addr == 0) { return NULL; } return pa_to_ka((void *)addr); } static void slob_print(void) { struct list_head *le = NULL; list_for_each(le, &slob_head) { slob_block_t *block = le_to_block(le); printk("Addr: %08X length: %d used: %d\n", block, block->length, block->allocated); } printk("\n"); } __UNUSED__ static void slob_test(void) { slob_print(); void *addr1 = kmalloc(100); void *addr2 = kmalloc(200); void *addr3 = kmalloc(300); kfree(addr2); kfree(addr3); void *addr4 = kmalloc(2220); void *addr5 = kmalloc(240); void *addr6 = kmalloc(2230); kfree(addr6); kfree(addr1); void *addr7 = kmalloc(220); void *addr8 = kmalloc(1200); kfree(addr4); kfree(addr8); kfree(addr7); kfree(addr5); kfree(addr6); slob_print(); } // slob 分配器初始化 void slob_init(void) { slob_block_t *block = __slob_alloc_pages(SLOB_PAGE_COUNT); assert(block != NULL, "Init_slob error! No memory!"); block->allocated = SLOB_FREE; block->length = SLOB_PAGE_COUNT * PAGE_SIZE - sizeof(slob_block_t); list_add(&block->list, &slob_head); //slob_test(); } // 切分内存块 static void split_chunk(slob_block_t *chunk_block, uint32_t len) { if (chunk_block->length - len > sizeof(slob_block_t) + SLOB_MIN_PART) { slob_block_t *new_chunk = (slob_block_t *)((uint32_t)chunk_block + sizeof(slob_block_t) + len); new_chunk->allocated = SLOB_FREE; new_chunk->length = chunk_block->length - len - sizeof(slob_block_t); list_add(&new_chunk->list, &chunk_block->list); chunk_block->length = len; chunk_block->allocated = SLOB_USED; } } // 合并内存块 static void glue_chunk(slob_block_t *chunk_block) { struct list_head *le = &chunk_block->list; if (le->prev != &slob_head) { slob_block_t *prev_block = le_to_block(le->prev); if (prev_block->allocated == SLOB_FREE) { prev_block->length += (chunk_block->length + sizeof(slob_block_t)); list_del(&chunk_block->list); chunk_block = prev_block; } } if (le->next != &slob_head) { slob_block_t *next_block = le_to_block(le->next); if (next_block->allocated == SLOB_FREE) { chunk_block->length += (next_block->length + sizeof(slob_block_t)); list_del(&next_block->list); } } } // 任意大小的内存分配函数 void *kmalloc(uint32_t size) { uint32_t len = (size > SLOB_MIN_PART) ? size : SLOB_MIN_PART; len += sizeof(slob_block_t); if (!list_empty(&slob_head)) { struct list_head *le = NULL; list_for_each(le, &slob_head) { slob_block_t *block = le_to_block(le); if (block->allocated == SLOB_FREE && block->length > len) { split_chunk(block, len); void *addr = (void *)((uint32_t)block + sizeof(slob_block_t)); return addr; } } } return NULL; } // 任意大小的内存释放函数 void kfree(void *addr) { slob_block_t *block = (slob_block_t *)((uint32_t)addr - sizeof(slob_block_t)); if (block->allocated != SLOB_USED) { return; } block->allocated = SLOB_FREE; glue_chunk(block); } ================================================ FILE: scripts/gdbinit ================================================ file hx_kernel target remote :1234 break kern_entry c ================================================ FILE: scripts/kernel.ld ================================================ /* * kernel.ld -- 针对 kernel 格式所写的链接脚本 * * qianyi.lh 2014/11/04 10:00:00 */ ENTRY(start) SECTIONS { . = 0x100000; PROVIDE(kern_start = .); PROVIDE(kern_init_text_start = .); .init.text : { *(.init.text) . = ALIGN(4096); } PROVIDE(kern_init_text_end = .); PROVIDE(kern_init_data_start = .); .init.data : { *(.init.data) . = ALIGN(4096); } PROVIDE(kern_init_data_end = .); . += 0xC0000000; PROVIDE(kern_text_start = . - 0xC0000000); .text : AT(ADDR(.text) - 0xC0000000) { *(.text) . = ALIGN(4096); } PROVIDE(kern_text_end = . - 0xC0000000); PROVIDE(kern_data_start = . - 0xC0000000); .data : AT(ADDR(.data) - 0xC0000000) { *(.data) *(.rodata) . = ALIGN(4096); } .bss : AT(ADDR(.bss) - 0xC0000000) { *(.bss) . = ALIGN(4096); } PROVIDE(kern_data_end = . - 0xC0000000); .stab : AT(ADDR(.stab) - 0xC0000000) { *(.stab) . = ALIGN(4096); } .stabstr : AT(ADDR(.stabstr) - 0xC0000000) { *(.stabstr) . = ALIGN(4096); } PROVIDE(kern_end = . - 0xC0000000); /DISCARD/ : { *(.comment) *(.eh_frame) } }