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