├── LICENCE
├── Makefile
├── README.md
├── boot
└── boot.s
├── floppy.img
├── fs
├── fs.c
└── initrd.c
├── gdt_idt
├── descriptor_tables.c
├── gdt.s
├── gdt_c.c
├── idt.s
├── idt_c.c
├── interupt.s
└── timer.c
├── include
├── common.h
├── descriptor_tables.h
├── fs.h
├── initrd.h
├── keyboard.h
├── memory.h
├── memory_manager.h
├── memory_pool.h
├── monitor.h
├── multiboot.h
├── sched.h
├── syscall.h
├── timer.h
└── virtual_memory.h
├── init
└── main.c
├── initrd.img
├── kernels
├── mm_clone.s
├── process.c
├── schedule.c
├── syscall.c
└── task_switch.s
├── lib
├── common.c
├── keyboard.c
└── monitor.c
├── mm
├── memory_manager.c
├── memory_pool.c
├── memory_tool.c
├── print_memory.c
└── virtual_memory.c
└── scripts
└── kernel.ld
/LICENCE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #!Makefile
2 |
3 | # patsubst 处理所有在 C_SOURCES 字列中的字(一列文件名),如果它的 结尾是 '.c',就用 '.o' 把 '.c' 取代
4 | C_SOURCES = $(shell find . -name "*.c")
5 | C_OBJECTS = $(patsubst %.c, %.o, $(C_SOURCES))
6 | S_SOURCES = $(shell find . -name "*.s")
7 | S_OBJECTS = $(patsubst %.s, %.o, $(S_SOURCES))
8 |
9 | CC = gcc
10 | LD = ld
11 | ASM = nasm
12 |
13 | C_FLAGS = -c -Wall -m32 -ggdb -gstabs+ -nostdinc -fno-builtin -fno-stack-protector -I include
14 | LD_FLAGS = -T scripts/kernel.ld -m elf_i386 -nostdlib
15 | ASM_FLAGS = -f elf -g -F stabs
16 |
17 | all: $(S_OBJECTS) $(C_OBJECTS) link update_image
18 |
19 | # The automatic variable `$<' is just the first prerequisite
20 | .c.o:
21 | @echo 编译代码文件 $< ...
22 | $(CC) $(C_FLAGS) $< -o $@
23 |
24 | .s.o:
25 | @echo 编译汇编文件 $< ...
26 | $(ASM) $(ASM_FLAGS) $<
27 |
28 | link:
29 | @echo 链接内核文件...
30 | $(LD) $(LD_FLAGS) $(S_OBJECTS) $(C_OBJECTS) -o kernel
31 |
32 | .PHONY:clean
33 | clean:
34 | $(RM) $(S_OBJECTS) $(C_OBJECTS) kernel
35 |
36 | .PHONY:update_image
37 | update_image:
38 | sudo /sbin/losetup /dev/loop0 floppy.img
39 | sudo mount /dev/loop0 /mnt
40 | sudo cp kernel /mnt/kernel
41 | sudo cp initrd.img /mnt/initrd
42 | sudo umount /dev/loop0
43 | sudo /sbin/losetup -d /dev/loop0
44 |
45 | .PHONY:mount_image
46 | mount_image:
47 | sudo mount floppy.img /mnt/kernel
48 |
49 | .PHONY:umount_image
50 | umount_image:
51 | sudo umount /mnt/kernel
52 |
53 | .PHONY:qemu
54 | qemu:
55 | qemu -fda floppy.img -boot a
56 |
57 | .PHONY:bochs
58 | bochs:
59 | bochs -f scripts/bochsrc.txt
60 |
61 | .PHONY:debug
62 | debug:
63 | qemu -S -s -fda floppy.img -boot a &
64 | sleep 1
65 | cgdb -x scripts/gdbinit
66 |
67 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # batboy-mini-kernel
2 | 一个自己实现的基本而有简单的操作系统。
3 | /fs : 实现了vfs的接口
4 | /boot : 初始的boot代码
5 | /gdt_idt : 实现了分段,中断,计时等
6 | /include : 各类头文件
7 | /init : main主函数
8 | /kernels : 进程,线程调度,系统调用等
9 | /lib : 键盘输入,显示输出等实现
10 | /mm : 内存管理,包括物理内存和分页后的虚拟内存
11 | /scripts : gcc链接脚本
12 |
13 | ###编译和启动
14 | 内核使用grub加载,运行在qemu模拟器上。
15 | 编译:
16 | ```
17 | $ make
18 | ```
19 | 启动:
20 | ```
21 | $ make qemu
22 | ```
--------------------------------------------------------------------------------
/boot/boot.s:
--------------------------------------------------------------------------------
1 | ;内核的开始地址
2 |
3 | ;魔数magic
4 | MultiBoot_Magic EQU 0x1BADB002 ;这个是grub可以识别的规范
5 | ;flags可以指出引导程序支持的特性
6 | MultiBoot_Flags EQU 0x00000003 ;第0位和1位设置为1是为了4kb对齐和men*_域包含可用内存信息
7 | ;magic,flags和checksum的和必须为0
8 | MultiBoot_Checksum EQU -(MultiBoot_Magic+MultiBoot_Flags)
9 |
10 | [BITS 32] ;代码以32位编译
11 | section .init.text ;代码段开始的地方
12 |
13 | dd MultiBoot_Magic
14 | dd MultiBoot_Flags
15 | dd MultiBoot_Checksum
16 |
17 | [GLOBAL start] ;外部可见的内核代码开始入口
18 | [GLOBAL glb_mboot_ptr_tmp];struct multiboot *变量
19 | [EXTERN entry] ;声明内核c代码的入口函数
20 |
21 | start:
22 | cli ;关中断
23 | mov [glb_mboot_ptr_tmp], ebx
24 | mov esp,STACK_TOP;吧esp的值保存的栈顶
25 | and esp,0FFFFFFF0H;按16字节对齐
26 | mov ebp,0
27 | call entry
28 |
29 | section .init.data ;data段开始了,data就是已经被初始化的全局变量
30 | stack: times 1024 db 0 ;临时内核栈
31 | STACK_TOP EQU $-stack-1 ;$代表当前地址
32 | glb_mboot_ptr_tmp: dd 0
33 |
34 |
--------------------------------------------------------------------------------
/floppy.img:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luohaha/batboy-mini-kernel/cf2661e47c5e8ddac53a37637c5a695525e94452/floppy.img
--------------------------------------------------------------------------------
/fs/fs.c:
--------------------------------------------------------------------------------
1 | #include "fs.h"
2 | fs_node_t *fs_root = 0; // The root of the filesystem.
3 |
4 | unsigned int read_fs(fs_node_t *node, unsigned int offset, unsigned int size, unsigned char *buffer)
5 | //读取索引节点node的文件数据,读取从offset位置开始,大小为size的数据
6 | //将他们写到buffer中
7 | {
8 | if (node->read != 0)
9 | //有读函数
10 | return node->read(node, offset, size, buffer);
11 | else
12 | return 0;
13 | }
14 |
15 | unsigned int write_fs(fs_node_t *node, unsigned int offset, unsigned int size, unsigned char *buffer)
16 | //同理,将buffer数据写到,文件从offset开始,长度size的区域
17 | {
18 | if (node->write != 0)
19 | return node->write(node, offset, size, buffer);
20 | else
21 | return 0;
22 | }
23 |
24 | void open_fs(fs_node_t *node, unsigned char read, unsigned char write)
25 | //打开文件
26 | {
27 | if (node->open != 0)
28 | return node->open(node);
29 | }
30 |
31 | void close_fs(fs_node_t *node)
32 | {
33 | if (node->close != 0)
34 | return node->close(node);
35 | }
36 |
37 | struct dirent *readdir_fs(fs_node_t *node, unsigned int index)
38 | //返回目录文件的所有目录项的起始地址
39 | {
40 | if ( (node->flags&0x7) == FS_DIRECTORY &&
41 | node->readdir != 0 )
42 | return node->readdir(node, index);
43 | else
44 | return 0;
45 | }
46 |
47 | fs_node_t *finddir_fs(fs_node_t *node, char *name)
48 | //寻找目录文件下,名字为name的文件的inode项
49 | {
50 | if ( (node->flags&0x7) == FS_DIRECTORY &&
51 | node->finddir != 0 )
52 | return node->finddir(node, name);
53 | else
54 | return 0;
55 | }
56 |
--------------------------------------------------------------------------------
/fs/initrd.c:
--------------------------------------------------------------------------------
1 | #include "initrd.h"
2 | #include "memory.h"
3 |
4 | initrd_header_t *initrd_header; // The header.
5 | initrd_file_header_t *file_headers; // 指向文件们
6 | fs_node_t *initrd_root; // root文件夹
7 | fs_node_t *initrd_dev; // 挂载点文件夹
8 | fs_node_t *root_nodes; // 文件数组的头地址
9 | int nroot_nodes; // 文件个数
10 |
11 | struct dirent dirent;
12 |
13 | static unsigned int initrd_read(fs_node_t *node, unsigned int offset, unsigned int size, unsigned char *buffer)
14 | {
15 | initrd_file_header_t header = file_headers[node->inode];
16 | //找到对应inode号的文件头信息
17 | if (offset > header.length)
18 | return 0;
19 | if (offset+size > header.length)
20 | //读取的位置不能超过文件的范围
21 | size = header.length-offset;
22 | memcpy(buffer, (unsigned char*) (header.offset+offset), size);
23 | //header.offset是文件的起始地址
24 | return size;
25 | }
26 |
27 | static unsigned int initrd_write(fs_node_t *node,unsigned int offset,unsigned int size,unsigned char *buffer)
28 | {
29 | initrd_file_header_t header = file_headers[node->inode];
30 | if(offset>header.length)
31 | return 0;
32 | if(size>strlen(buffer))
33 | size=strlen(buffer);
34 | file_headers[node->inode].length=offset+strlen(buffer);
35 | root_nodes[node->inode].length=offset+strlen(buffer);
36 | memcpy((unsigned char*)(header.offset+offset),buffer,size);
37 | return size;
38 | }
39 |
40 | static struct dirent *initrd_readdir(fs_node_t *node, unsigned int index)
41 | {
42 | if (node == initrd_root && index == 0)
43 | //创建根节点下/dev目录文件的目录项
44 | {
45 | strcpy(dirent.name, "dev");
46 | dirent.name[3] = 0;
47 | dirent.ino = 0;
48 | return &dirent;
49 | }
50 |
51 | if (index-1 >= nroot_nodes)
52 | //超过了文件数,没有indoe号为index的文件
53 | return 0;
54 | //新建一个目录项,将找到的文件的信息存进去
55 | strcpy(dirent.name, root_nodes[index-1].name);
56 | dirent.name[strlen(root_nodes[index-1].name)] = 0;
57 | dirent.ino = root_nodes[index-1].inode;
58 | return &dirent;
59 | }
60 |
61 | static fs_node_t *initrd_finddir(fs_node_t *node, char *name)
62 | {
63 | //如果是找/dev的话
64 | if (node == initrd_root &&
65 | !strcmp(name, "dev") )
66 | return initrd_dev;
67 |
68 | int i;
69 | //找普通文件
70 | for (i = 0; i < nroot_nodes; i++)
71 | if (!strcmp(name, root_nodes[i].name))
72 | return &root_nodes[i];
73 | return 0;
74 | }
75 |
76 | fs_node_t *initialise_initrd(unsigned int location)
77 | {
78 | /*
79 | 因为在创建的initrd.img文件中,数据是按以下
80 | 方式创建的:
81 | 1.initrd_header_t,致命有多少文件
82 | 2.initrd_file_header_t,文件的信息文件
83 | 从这个文件中,可以读出包括文件实际位置在内的信息
84 | 3.文件实在的数据
85 | 所以在一下的初始化中,按照multiboot指出的起始位置,
86 | 可以依次读出相关信息
87 | */
88 | initrd_header = (initrd_header_t *)location;
89 | file_headers = (initrd_file_header_t *) (location+sizeof(initrd_header_t));
90 |
91 | // Initialise the root directory.
92 | initrd_root = (fs_node_t*)kmalloc(sizeof(fs_node_t));
93 | strcpy(initrd_root->name, "initrd");
94 | initrd_root->mask = initrd_root->uid = initrd_root->gid = initrd_root->inode = initrd_root->length = 0;
95 | initrd_root->flags = FS_DIRECTORY;
96 | initrd_root->read = 0;
97 | initrd_root->write = 0;
98 | initrd_root->open = 0;
99 | initrd_root->close = 0;
100 | initrd_root->readdir = &initrd_readdir;
101 | initrd_root->finddir = &initrd_finddir;
102 | initrd_root->ptr = 0;
103 | initrd_root->impl = 0;
104 |
105 | // Initialise the /dev directory (required!)
106 | initrd_dev = (fs_node_t*)kmalloc(sizeof(fs_node_t));
107 | strcpy(initrd_dev->name, "dev");
108 | initrd_dev->mask = initrd_dev->uid = initrd_dev->gid = initrd_dev->inode = initrd_dev->length = 0;
109 | initrd_dev->flags = FS_DIRECTORY;
110 | initrd_dev->read = 0;
111 | initrd_dev->write = 0;
112 | initrd_dev->open = 0;
113 | initrd_dev->close = 0;
114 | initrd_dev->readdir = &initrd_readdir;
115 | initrd_dev->finddir = &initrd_finddir;
116 | initrd_dev->ptr = 0;
117 | initrd_dev->impl = 0;
118 |
119 | root_nodes = (fs_node_t*)kmalloc(sizeof(fs_node_t) * initrd_header->nfiles);
120 | nroot_nodes = initrd_header->nfiles;
121 |
122 | // For every file...
123 | int i;
124 | for (i = 0; i < initrd_header->nfiles; i++)
125 | {
126 | // Edit the file's header - currently it holds the file offset
127 | // relative to the start of the ramdisk. We want it relative to the start
128 | // of memory.
129 | file_headers[i].offset += location;
130 | // Create a new file node.
131 | strcpy(root_nodes[i].name, &file_headers[i].name);
132 | root_nodes[i].mask = root_nodes[i].uid = root_nodes[i].gid = 0;
133 | root_nodes[i].length = file_headers[i].length;
134 | root_nodes[i].inode = i;
135 | root_nodes[i].flags = FS_FILE;
136 | root_nodes[i].read = &initrd_read;
137 | root_nodes[i].write = &initrd_write;
138 | root_nodes[i].readdir = 0;
139 | root_nodes[i].finddir = 0;
140 | root_nodes[i].open = 0;
141 | root_nodes[i].close = 0;
142 | root_nodes[i].impl = 0;
143 | }
144 | return initrd_root;
145 | }
146 |
--------------------------------------------------------------------------------
/gdt_idt/descriptor_tables.c:
--------------------------------------------------------------------------------
1 | /*
2 | 初始化gdt与idt,定义默认的isr和irq
3 | */
4 | #include "common.h"
5 | #include "descriptor_tables.h"
6 | #include "monitor.h"
7 | //extern void gdt_flush(unsigned int);
8 | //extern void idt_flush(unsigned int);
9 | extern void init_idt();
10 | extern void init_gdt();
11 |
12 |
13 |
14 |
15 | void init_descriptor_tables()
16 | {
17 | init_gdt();
18 | init_idt();
19 | }
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/gdt_idt/gdt.s:
--------------------------------------------------------------------------------
1 | [GLOBAL gdt_flush]
2 |
3 | gdt_flush:
4 | mov eax,[esp+4];
5 | lgdt [eax]
6 | ;kernel data seg is 0x10,code seg is 0x08
7 | mov ax,0x10 ;
8 | mov ds,ax
9 | mov es,ax
10 | mov fs,ax
11 | mov gs,ax
12 | mov ss,ax
13 | jmp 0x08:.flush
14 | .flush:
15 | ret
16 |
17 | [GLOBAL tss_flush]
18 |
19 | tss_flush:
20 | mov ax, 0x2b ;tss段起始是0x28,后两位置1,得0x2b
21 | ltr ax
22 | ret
23 |
--------------------------------------------------------------------------------
/gdt_idt/gdt_c.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 | #include "descriptor_tables.h"
3 | #include "monitor.h"
4 | #include "syscall.h"
5 | static void gdt_set_gate(unsigned int,unsigned int,unsigned int,unsigned char,unsigned char);
6 | static void write_tss(unsigned int num, unsigned short ss0,unsigned int esp0);
7 | extern void tss_flush();
8 | void init_gdt();
9 | gdt_entry gdt_entries[6];//定义5个段
10 | gdt_ptr the_gdt_ptr; //定义段表开始地址及长度
11 | tss_t tss_entry;//定义一个tss段
12 | void init_gdt()
13 | {
14 | the_gdt_ptr.limit=(sizeof(gdt_entry)*6)-1;
15 | the_gdt_ptr.base=(unsigned int)&gdt_entries;
16 |
17 | gdt_set_gate(0, 0, 0, 0, 0); // Null segment
18 | gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment
19 | gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment
20 | gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment
21 | gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment
22 | write_tss(5,0x10,0x0);//add tss段
23 | gdt_flush((unsigned int)&the_gdt_ptr);
24 | tss_flush();
25 | }
26 | static void gdt_set_gate(unsigned int num,unsigned int base,unsigned int limit,unsigned char access,unsigned char gran)
27 | {
28 | //用了定义entry具体内容的函数
29 | gdt_entries[num].base_low = (base & 0xFFFF);
30 | gdt_entries[num].base_middle = (base >> 16) & 0xFF;
31 | gdt_entries[num].base_high = (base >> 24) & 0xFF;
32 |
33 | gdt_entries[num].limit_low = (limit & 0xFFFF);
34 | gdt_entries[num].granularity = (limit >> 16) & 0x0F;
35 |
36 | gdt_entries[num].granularity |= gran & 0xF0;
37 | gdt_entries[num].access = access;
38 | }
39 |
40 | static void write_tss(unsigned int num, unsigned short ss0, unsigned int esp0)
41 | {
42 | unsigned int base = (unsigned int) &tss_entry;
43 | unsigned int limit=base+sizeof(tss_t);
44 | gdt_set_gate(num,base,limit,0xE9,0x00);
45 | memset(&tss_entry,0,sizeof(tss_t));
46 | tss_entry.ss0=ss0;
47 | tss_entry.esp0=esp0;
48 | //因为首先是内核模式,所以代码段是0x08数据段是0x10
49 | //将后两位(rpl)置1,所以是0x0b和0x13
50 | tss_entry.ss=tss_entry.ds=tss_entry.es=tss_entry.gs=tss_entry.fs=0x13;
51 | //代码段
52 | tss_entry.cs=0x0b;
53 | }
54 | void set_kernel_stack(unsigned int stack)
55 | {
56 | tss_entry.esp0=stack;
57 | }
58 |
--------------------------------------------------------------------------------
/gdt_idt/idt.s:
--------------------------------------------------------------------------------
1 | [GLOBAL idt_flush]
2 |
3 |
4 | idt_flush:
5 | mov eax,[esp+4]
6 | lidt [eax]
7 | ret
8 |
9 |
10 |
--------------------------------------------------------------------------------
/gdt_idt/idt_c.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 | #include "descriptor_tables.h"
3 | #include "monitor.h"
4 | extern void memset(void* addr,unsigned char ch,unsigned int size);
5 | void init_idt();
6 | static void idt_set_gate(unsigned char,unsigned int,unsigned short,unsigned char);
7 | idt_entry idt_entries[256];//定义256个中断
8 | idt_ptr the_idt_ptr; //定义中断表的开始及长度
9 | interrupt_handler_t interrupt_handlers[256];//中断处理函数的指针数组
10 | void init_idt()
11 | {
12 |
13 | memset((unsigned char *)&interrupt_handlers,0,sizeof(interrupt_handler_t)*256);
14 | the_idt_ptr.limit=sizeof(idt_entry)*256-1;
15 | the_idt_ptr.base=(unsigned int)&idt_entries;
16 | memset((unsigned char *)&idt_entries,0,sizeof(idt_entry)*256);
17 | //////////////////////////////////////
18 | //初始化irq以及对irq中断号重新布局
19 | //0x20和0xA0口分别为master pic 与slaver pic的控制端口
20 | //0x21和0xA1口分别位master pic 与slaver pic的控制数据传输端口
21 | //初始化pic们
22 | outb(0x20,0x11);
23 | outb(0xA0,0x11);
24 | //master pic从0x20(也就是32)中断号开始,slaver pic从0x28(40)中断号开始
25 | outb(0x21,0x20);
26 | outb(0xA1,0x28);
27 | //告诉master,slaver在第3个口(0x04)
28 | outb(0x21,0x04);
29 | outb(0xA1,0x02);
30 | //设置按照8086方式工作
31 | outb(0x21,0x01);
32 | outb(0xA1,0x01);
33 | //设置允许中断
34 | outb(0x21,0x0);
35 | outb(0xA1,0x0);
36 | //////////////////////
37 | //异常结构中断处理初始化
38 | idt_set_gate(0,(unsigned int)isr0,0x08,0x8E);
39 | idt_set_gate(1,(unsigned int)isr1,0x08,0x8E);
40 | idt_set_gate(2,(unsigned int)isr2,0x08,0x8E);
41 | idt_set_gate(3,(unsigned int)isr3,0x08,0x8E);
42 | idt_set_gate(4,(unsigned int)isr4,0x08,0x8E);
43 | idt_set_gate(5,(unsigned int)isr5,0x08,0x8E);
44 | idt_set_gate(6,(unsigned int)isr6,0x08,0x8E);
45 | idt_set_gate(7,(unsigned int)isr7,0x08,0x8E);
46 | idt_set_gate(8,(unsigned int)isr8,0x08,0x8E);
47 | idt_set_gate(9,(unsigned int)isr9,0x08,0x8E);
48 | idt_set_gate(10,(unsigned int)isr10,0x08,0x8E);
49 | idt_set_gate(11,(unsigned int)isr11,0x08,0x8E);
50 | idt_set_gate(12,(unsigned int)isr12,0x08,0x8E);
51 | idt_set_gate(13,(unsigned int)isr13,0x08,0x8E);
52 | idt_set_gate(14,(unsigned int)isr14,0x08,0x8E);
53 | idt_set_gate(15,(unsigned int)isr15,0x08,0x8E);
54 | idt_set_gate(16,(unsigned int)isr16,0x08,0x8E);
55 | idt_set_gate(17,(unsigned int)isr17,0x08,0x8E);
56 | idt_set_gate(18,(unsigned int)isr18,0x08,0x8E);
57 | idt_set_gate(19,(unsigned int)isr19,0x08,0x8E);
58 | idt_set_gate(20,(unsigned int)isr20,0x08,0x8E);
59 | idt_set_gate(21,(unsigned int)isr21,0x08,0x8E);
60 | idt_set_gate(22,(unsigned int)isr22,0x08,0x8E);
61 | idt_set_gate(23,(unsigned int)isr23,0x08,0x8E);
62 | idt_set_gate(24,(unsigned int)isr24,0x08,0x8E);
63 | idt_set_gate(25,(unsigned int)isr25,0x08,0x8E);
64 | idt_set_gate(26,(unsigned int)isr26,0x08,0x8E);
65 | idt_set_gate(27,(unsigned int)isr27,0x08,0x8E);
66 | idt_set_gate(28,(unsigned int)isr28,0x08,0x8E);
67 | idt_set_gate(29,(unsigned int)isr29,0x08,0x8E);
68 | idt_set_gate(30,(unsigned int)isr30,0x08,0x8E);
69 | idt_set_gate(31,(unsigned int)isr31,0x08,0x8E);
70 | //系统中断
71 | idt_set_gate(128,(unsigned int)isr128,0x08,0x8E);
72 | //中断请求中断结构初始化
73 | idt_set_gate(32, (unsigned int)irq0, 0x08, 0x8E);
74 | idt_set_gate(33, (unsigned int)irq1, 0x08, 0x8E);
75 | idt_set_gate(34, (unsigned int)irq2, 0x08, 0x8E);
76 | idt_set_gate(35, (unsigned int)irq3, 0x08, 0x8E);
77 | idt_set_gate(36, (unsigned int)irq4, 0x08, 0x8E);
78 | idt_set_gate(37, (unsigned int)irq5, 0x08, 0x8E);
79 | idt_set_gate(38, (unsigned int)irq6, 0x08, 0x8E);
80 | idt_set_gate(39, (unsigned int)irq7, 0x08, 0x8E);
81 | idt_set_gate(40, (unsigned int)irq8, 0x08, 0x8E);
82 | idt_set_gate(41, (unsigned int)irq9, 0x08, 0x8E);
83 | idt_set_gate(42, (unsigned int)irq10, 0x08, 0x8E);
84 | idt_set_gate(43, (unsigned int)irq11, 0x08, 0x8E);
85 | idt_set_gate(44, (unsigned int)irq12, 0x08, 0x8E);
86 | idt_set_gate(45, (unsigned int)irq13, 0x08, 0x8E);
87 | idt_set_gate(46, (unsigned int)irq14, 0x08, 0x8E);
88 | idt_set_gate(47, (unsigned int)irq15, 0x08, 0x8E);
89 | idt_flush((unsigned int)&the_idt_ptr);
90 | }
91 | static void idt_set_gate(unsigned char num,unsigned int base,unsigned short sel,unsigned char flags)
92 | {
93 | idt_entries[num].base_low=base&0xFFFF;
94 | idt_entries[num].base_high=(base>>16)&0xFFFF;
95 |
96 | idt_entries[num].sel=sel;
97 | idt_entries[num].always0=0;
98 | idt_entries[num].flags=flags;
99 | }
100 | //异常中断首先调用的函数
101 | void isr_handler(registers_t *regs)
102 | {
103 | if(interrupt_handlers[regs->int_no])
104 | {
105 | interrupt_handlers[regs->int_no](regs);
106 | }
107 | else
108 | {
109 | printf("not int is:",0);
110 | printf("%d",regs->int_no);
111 | }
112 | }
113 | //中断请求调用的函数
114 | void irq_handler(registers_t *regs)
115 | {
116 | if(regs->int_no>=40)
117 | //slave pic
118 | {
119 | outb(0xA0,0x20);//reset 信号
120 | }
121 | outb(0x20,0x20);//reset
122 | if(interrupt_handlers[regs->int_no])
123 | {
124 | interrupt_handlers[regs->int_no](regs);
125 | }
126 |
127 | }
128 | //中断处理注册函数
129 | void register_int_handler(unsigned char num, interrupt_handler_t h)
130 | {
131 | interrupt_handlers[num]=h;
132 | }
133 |
--------------------------------------------------------------------------------
/gdt_idt/interupt.s:
--------------------------------------------------------------------------------
1 | %macro ISR_NOERR 1
2 | [GLOBAL isr%1]
3 | isr%1:
4 | cli
5 | push byte 0
6 | push byte %1
7 | jmp isr_common_stub
8 | %endmacro
9 |
10 | %macro ISR_ERR 1
11 | [GLOBAL isr%1]
12 | isr%1:
13 | cli;
14 | push byte %1
15 | jmp isr_common_stub
16 | %endmacro
17 |
18 | %macro IRQ 2
19 | [GLOBAL irq%1]
20 | irq%1:
21 | cli;
22 | push byte 0
23 | push byte %2
24 | jmp irq_common_stub
25 | %endmacro
26 |
27 | ISR_NOERR 0
28 | ISR_NOERR 1
29 | ISR_NOERR 2
30 | ISR_NOERR 3
31 | ISR_NOERR 4
32 | ISR_NOERR 5
33 | ISR_NOERR 6
34 | ISR_NOERR 7
35 | ISR_ERR 8
36 | ISR_NOERR 9
37 | ISR_ERR 10
38 | ISR_ERR 11
39 | ISR_ERR 12
40 | ISR_ERR 13
41 | ISR_ERR 14
42 | ISR_NOERR 15
43 | ISR_NOERR 16
44 | ISR_ERR 17
45 | ISR_NOERR 18
46 | ISR_NOERR 19
47 |
48 | ISR_NOERR 20
49 | ISR_NOERR 21
50 | ISR_NOERR 22
51 | ISR_NOERR 23
52 | ISR_NOERR 24
53 | ISR_NOERR 25
54 | ISR_NOERR 26
55 | ISR_NOERR 27
56 | ISR_NOERR 28
57 | ISR_NOERR 29
58 | ISR_NOERR 30
59 | ISR_NOERR 31
60 | ; 32 ~ 255 用户自定
61 | ISR_NOERR 128
62 |
63 | IRQ 0, 32 ; 电脑系统计时器
64 | IRQ 1, 33 ; 键盘
65 | IRQ 2, 34 ; 与 IRQ9 相接,MPU-401 MD 使用
66 | IRQ 3, 35 ; 串口设备
67 | IRQ 4, 36 ; 串口设备
68 | IRQ 5, 37 ; 建议声卡使用
69 | IRQ 6, 38 ; 软驱传输控制使用
70 | IRQ 7, 39 ; 打印机传输控制使用
71 | IRQ 8, 40 ; 即时时钟
72 | IRQ 9, 41 ; 与 IRQ2 相接,可设定给其他硬件
73 | IRQ 10, 42 ; 建议网卡使用
74 | IRQ 11, 43 ; 建议 AGP 显卡使用
75 | IRQ 12, 44 ; 接 PS/2 鼠标,也可设定给其他硬件
76 | IRQ 13, 45 ; 协处理器使用
77 | IRQ 14, 46 ; IDE0 传输控制使用
78 | IRQ 15, 47 ; IDE1 传输控制使用
79 |
80 | [GLOBAL isr_common_stub]
81 | [EXTERN isr_handler]
82 |
83 | isr_common_stub:
84 | pusha
85 | mov ax,ds
86 | push eax
87 | mov ax, 0x10 ; load the kernel data segment descriptor
88 | mov ds, ax
89 | mov es, ax
90 | mov fs, ax
91 | mov gs, ax
92 | mov ss, ax
93 |
94 | push esp
95 | call isr_handler
96 | add esp, 4
97 |
98 | pop ebx ; reload the original data segment descriptor
99 | mov ds, bx
100 | mov es, bx
101 | mov fs, bx
102 | mov gs, bx
103 | mov ss, bx
104 |
105 | popa ; Pops edi,esi,ebp...
106 | add esp, 8 ; Cleans up the pushed error code and pushed ISR number
107 | sti
108 | iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
109 |
110 | [GLOBAL irq_common_stub]
111 | [EXTERN irq_handler]
112 |
113 | irq_common_stub:
114 | pusha
115 | mov ax,ds
116 | push eax
117 | mov ax, 0x10 ; load the kernel data segment descriptor
118 | mov ds, ax
119 | mov es, ax
120 | mov fs, ax
121 | mov gs, ax
122 | mov ss, ax
123 |
124 | push esp
125 | call irq_handler
126 | add esp, 4
127 |
128 | pop ebx ; reload the original data segment descriptor
129 | mov ds, bx
130 | mov es, bx
131 | mov fs, bx
132 | mov gs, bx
133 | mov ss, bx
134 |
135 | popa ; Pops edi,esi,ebp...
136 | add esp, 8 ; Cleans up the pushed error code and pushed ISR number
137 | sti
138 | iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
139 |
--------------------------------------------------------------------------------
/gdt_idt/timer.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 | #include "timer.h"
3 | #include "descriptor_tables.h"
4 | #include "monitor.h"
5 | #include "sched.h"
6 | unsigned int count=0;
7 | void timer_count(registers_t *regs)
8 | {
9 | count++;
10 | printf("\n",0);
11 | // printf("%d",regs->int_no);
12 | // printf("\n这是第几次?\n",0);
13 | printf("%d",count);
14 | printf("\n",0);
15 | }
16 | void sche(registers_t *regs)
17 | {
18 | schedule();
19 | }
20 | void init_timer(unsigned int frequency)
21 | {
22 | //printf(" 准备计时\n",0);
23 | //把timer_count函数注册到中断32号口(irq0口)
24 | register_int_handler(32,sche);
25 | unsigned int div=1193180/frequency;
26 | //pit有四个端口,0x40~0x42是对应0~2频道,0x43对应命令口
27 | //准备传输
28 | outb(0x43,0x36);
29 | unsigned char low=(unsigned char)(div & 0xff);//低八位
30 | unsigned char high=(unsigned char)((div>>8) & 0xff);//高八位
31 |
32 | //分别传输
33 | outb(0x40,low);
34 | outb(0x40,high);
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/include/common.h:
--------------------------------------------------------------------------------
1 | #ifndef COMMON_H
2 | //如果没有定义过这个的话~~ifndef用于判断是否重复定义
3 | #define COMMON_H
4 |
5 | #ifndef NULL
6 | #define NULL 0
7 | #endif
8 |
9 | #ifndef TRUE
10 | #define TRUE 1
11 | #define FALSE 0
12 | #endif
13 |
14 | void outb(unsigned short port,unsigned char value);
15 | unsigned char inb(unsigned short port);
16 | unsigned short inw(unsigned short port);
17 |
18 | #endif
19 |
--------------------------------------------------------------------------------
/include/descriptor_tables.h:
--------------------------------------------------------------------------------
1 | /*
2 | * 段gdt
3 | *
4 | */
5 | #ifndef DESCRIPTOR_TABLES_H
6 | #define DESCRIPTOR_TABLES_H
7 |
8 | #include "common.h"
9 |
10 | struct gdt_entry_struct
11 | {
12 | unsigned short limit_low;
13 | unsigned short base_low;
14 | unsigned char base_middle;
15 | unsigned char access;
16 | unsigned char granularity;
17 | unsigned char base_high;
18 | }__attribute__((packed)) gdt_entry_struct;
19 | typedef struct gdt_entry_struct gdt_entry;
20 |
21 | struct gdt_ptr_struct
22 | {
23 | unsigned short limit;
24 | unsigned int base;
25 | }__attribute__((packed)) gdt_ptr_struct;
26 | typedef struct gdt_ptr_struct gdt_ptr;
27 |
28 | extern void gdt_flush(unsigned int);
29 |
30 | /*
31 | * 中断的实现的相关定义
32 | *
33 | */
34 | void init_descriptor_tables();
35 |
36 | struct idt_entry_struct
37 | {
38 | unsigned short base_low;//lower 16bit
39 | unsigned short sel; //kernel seg selector
40 | unsigned char always0;
41 | unsigned char flags;
42 | unsigned short base_high;//high 16bit
43 | }__attribute__((packed)) idt_entry_struct;
44 | typedef struct idt_entry_struct idt_entry;
45 |
46 | struct idt_ptr_struct
47 | {
48 | unsigned short limit;
49 | unsigned int base;
50 | }__attribute__((packed)) idt_ptr_struct;
51 | typedef struct idt_ptr_struct idt_ptr;
52 | //
53 | typedef struct registers
54 | {
55 | unsigned int ds; // Data segment selector
56 | unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha.
57 | unsigned int int_no, err_code; // Interrupt number and error code (if applicable)
58 | unsigned int eip, cs, eflags, useresp, ss; // Pushed by the processor automatically.
59 | }registers_t;
60 |
61 | typedef void (*interrupt_handler_t)(registers_t *);
62 |
63 | void isr0(); // 0 #DE 除 0 异常
64 | void isr1(); // 1 #DB 调试异常
65 | void isr2(); // 2 NMI
66 | void isr3(); // 3 BP 断点异常
67 | void isr4(); // 4 #OF 溢出
68 | void isr5(); // 5 #BR 对数组的引用超出边界
69 | void isr6(); // 6 #UD 无效或未定义的操作码
70 | void isr7(); // 7 #NM 设备不可用(无数学协处理器)
71 | void isr8(); // 8 #DF 双重故障(有错误代码)
72 | void isr9(); // 9 协处理器跨段操作
73 | void isr10(); // 10 #TS 无效TSS(有错误代码)
74 | void isr11(); // 11 #NP 段不存在(有错误代码)
75 | void isr12(); // 12 #SS 栈错误(有错误代码)
76 | void isr13(); // 13 #GP 常规保护(有错误代码)
77 | void isr14(); // 14 #PF 页故障(有错误代码)
78 | void isr15(); // 15 CPU 保留
79 | void isr16(); // 16 #MF 浮点处理单元错误
80 | void isr17(); // 17 #AC 对齐检查
81 | void isr18(); // 18 #MC 机器检查
82 | void isr19(); // 19 #XM SIMD(单指令多数据)浮点异常
83 |
84 | // 20-31 Intel 保留
85 | void isr20();
86 | void isr21();
87 | void isr22();
88 | void isr23();
89 | void isr24();
90 | void isr25();
91 | void isr26();
92 | void isr27();
93 | void isr28();
94 | void isr29();
95 | void isr30();
96 | void isr31();
97 | //系统调用
98 | void isr128();
99 | // IRQ:中断请求(Interrupt Request)
100 | void irq0(); // 电脑系统计时器
101 | void irq1(); // 键盘
102 | void irq2(); // 与 IRQ9 相接,MPU-401 MD 使用
103 | void irq3(); // 串口设备
104 | void irq4(); // 串口设备
105 | void irq5(); // 建议声卡使用
106 | void irq6(); // 软驱传输控制使用
107 | void irq7(); // 打印机传输控制使用
108 | void irq8(); // 即时时钟
109 | void irq9(); // 与 IRQ2 相接,可设定给其他硬件
110 | void irq10(); // 建议网卡使用
111 | void irq11(); // 建议 AGP 显卡使用
112 | void irq12(); // 接 PS/2 鼠标,也可设定给其他硬件
113 | void irq13(); // 协处理器使用
114 | void irq14(); // IDE0 传输控制使用
115 | void irq15(); // IDE1 传输控制使用
116 | // 32 ~ 255 用户自定义异常
117 | //void isr255();
118 | extern void idt_flush(unsigned int);
119 | //异常发生时调用的函数
120 | void isr_handler(registers_t *regs);
121 | //中断请求时调用的函数
122 | void irq_handler(registers_t *regs);
123 | //注册对应中断号的中断处理函数
124 | void register_int_handler(unsigned char num, interrupt_handler_t h);
125 | #endif
126 |
--------------------------------------------------------------------------------
/include/fs.h:
--------------------------------------------------------------------------------
1 | #ifndef FS_H
2 | #define FS_H
3 |
4 | #include "common.h"
5 |
6 | #define FS_FILE 0x01//普通文件
7 | #define FS_DIRECTORY 0x02//目录文件
8 | #define FS_CHARDEVICE 0x03//字符型文件
9 | #define FS_BLOCKDEVICE 0x04//块文件,按数据块读写
10 | #define FS_PIPE 0x05//管道文件
11 | #define FS_SYMLINK 0x06//符号链接
12 | #define FS_MOUNTPOINT 0x08 // Is the file an active mountpoint?
13 |
14 | struct fs_node;
15 |
16 | //定义指向函数的指针,对应不同的文件系统,有不同的函数,使用这种方式可以
17 | //统一接口
18 | typedef unsigned int (*read_type_t)(struct fs_node*,unsigned int,unsigned int,unsigned char*);//读文件
19 | typedef unsigned int (*write_type_t)(struct fs_node*,unsigned int,unsigned int,unsigned char*);//写文件
20 | typedef void (*open_type_t)(struct fs_node*);//打开文件,然后可以接下其他动作
21 | typedef void (*close_type_t)(struct fs_node*);//关闭文件
22 | typedef struct dirent * (*readdir_type_t)(struct fs_node*,unsigned int);
23 | //获取目录文件信息,返回目录项指针,因为有很多的目录项(每个文件对应一个)
24 | typedef struct fs_node * (*finddir_type_t)(struct fs_node*,char *name);
25 | //找到文件
26 | typedef struct fs_node
27 | {
28 | char name[128]; // 文件名
29 | unsigned int mask; // 权限掩码,读写和执行
30 | unsigned int uid; // 用户id,user id
31 | unsigned int gid; // 组id,group id
32 | unsigned int flags; // 文件类型
33 | unsigned int inode; //文件id,唯一,用来表示不同的文件
34 | unsigned int length; // 文件大小(byte)
35 | unsigned int impl; // An implementation-defined number.
36 | read_type_t read;
37 | write_type_t write;
38 | open_type_t open;
39 | close_type_t close;
40 | readdir_type_t readdir;
41 | finddir_type_t finddir;
42 | struct fs_node *ptr; // 有符号链接时存在
43 | } fs_node_t;
44 |
45 | struct dirent//目录项
46 | //每个目录项对应一个名字和一个inode号,通过查找目录项,找到对应名字的文件的
47 | //inode号,然后再去查找inode,才能接下来的操作
48 | {
49 | char name[128]; // Filename.
50 | unsigned int ino; // Inode number. Required by POSIX.
51 | };
52 |
53 | extern fs_node_t *fs_root; // The root of the filesystem.
54 |
55 | // Standard read/write/open/close functions.
56 | //定义虚拟文件操作函数,屏蔽地下的实际的文件操作函数
57 | unsigned int read_fs(fs_node_t *node, unsigned int offset, unsigned int size, unsigned char *buffer);
58 | unsigned int write_fs(fs_node_t *node, unsigned int offset, unsigned int size, unsigned char *buffer);
59 | void open_fs(fs_node_t *node, unsigned char read, unsigned char write);
60 | void close_fs(fs_node_t *node);
61 | struct dirent *readdir_fs(fs_node_t *node, unsigned int index);
62 | fs_node_t *finddir_fs(fs_node_t *node, char *name);
63 |
64 | #endif
65 |
--------------------------------------------------------------------------------
/include/initrd.h:
--------------------------------------------------------------------------------
1 | #ifndef INITRD_H
2 | #define INITRD_H
3 |
4 | #include "common.h"
5 | #include "fs.h"
6 |
7 | typedef struct
8 | {
9 | unsigned int nfiles; // ramdisk中的文件数
10 | } initrd_header_t;
11 |
12 | typedef struct
13 | //文件格式信息
14 | {
15 | unsigned char magic; // Magic number
16 | unsigned char name[64]; // 文件名
17 | unsigned int offset; // 文件在内存中的偏离起始位置的
18 | //的大小,就是文件的地
19 | unsigned int length; // 文件的长度
20 | } initrd_file_header_t;
21 |
22 | // 初始化initrd,location 是起始地址,由multiboot中的
23 | //mods_addr给出,没错,就是那个神奇的multiboot
24 | //返回root的inode
25 | fs_node_t *initialise_initrd(unsigned int location);
26 |
27 | #endif
28 |
--------------------------------------------------------------------------------
/include/keyboard.h:
--------------------------------------------------------------------------------
1 | #ifndef KEYBOARD_H
2 | #define KEYBOARD_H
3 | #include "common.h"
4 | void init_keyboard();
5 |
6 | #endif
7 |
--------------------------------------------------------------------------------
/include/memory.h:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 |
3 | void memset(void *,unsigned char,unsigned int);
4 | void memcpy(unsigned char *str1,unsigned char *str2,unsigned int len);
5 | //把str2复制给str1
6 | int strcmp(unsigned char *str1,unsigned char *str2);
7 | unsigned char* strcpy(unsigned char *str1,unsigned char *str2);
8 | int strlen(unsigned char *c);
9 |
--------------------------------------------------------------------------------
/include/memory_manager.h:
--------------------------------------------------------------------------------
1 | /*
2 | 这个是物理内存分配,
3 | virtual_memory.h
4 | 定义的是虚拟内存分配,
5 | 所以,kernel采用的是虚拟内存分配(分页)
6 | ,最后,虚拟线性地址都要通过分页机制转换为物理内存地址,也就是下面所定义的
7 | */
8 | #ifndef MEMORY_MANAGER_H
9 | #define MEMORY_MANAGER_H
10 |
11 | #include "common.h"
12 | #include "multiboot.h"
13 | #define PAGE_SIZE 0x1000 //4KB
14 | #define STACK_SIZE 8192 //
15 | #define MAX_MEMORY_SIZE 0x20000000 //512MB
16 | #define PAGE_NUMBER (MAX_MEMORY_SIZE/PAGE_SIZE)
17 | //extern unsigned int page_count;//目前可以供使用的内存页面的数量
18 | //extern unsigned int page_stack[STACK_SIZE];//可用页面起始地址栈
19 |
20 | void print_memory();
21 | extern unsigned char kern_start[];
22 | extern unsigned char kern_end[];
23 |
24 | void init_memory();
25 | void memory_free(unsigned int addr);
26 | unsigned int memory_alloc();
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/include/memory_pool.h:
--------------------------------------------------------------------------------
1 | #ifndef MEMORY_POOL_H
2 | #define MEMORY_POOL_H
3 |
4 | #define POOL_BEGIN 0xE0000000
5 | typedef struct block_head{
6 | unsigned int length : 31;//内存块的长度,包括头部长度
7 | unsigned int used : 1;//是否已经使用,1是已经使用,0为未使用
8 | struct block_head *pre;
9 | struct block_head *next;
10 | }block_head;
11 | extern block_head *leader;
12 | void init_pool();
13 | void* kmalloc(unsigned int length);
14 | void kfree(unsigned int addr);
15 | void union_block(block_head *old);
16 | void cut(unsigned int addr,unsigned int length,block_head *prev);
17 | void* alloc(unsigned int length,block_head *prev);
18 | void pool_test();
19 | #endif
20 |
--------------------------------------------------------------------------------
/include/monitor.h:
--------------------------------------------------------------------------------
1 | #ifndef MONITOR_H
2 | #define MONITOR_H
3 |
4 | #include "common.h"
5 |
6 | //在屏幕上输出一个字符
7 | void monitor_put(char c);
8 | //清屏
9 | void monitor_clear();
10 | //在屏幕上输出字符串
11 | void monitor_str(char *c);
12 | void monitor_hex(unsigned int c);
13 | void monitor_dec(unsigned int c);
14 | void printf(char *s,unsigned int c);
15 | #endif
16 |
--------------------------------------------------------------------------------
/include/multiboot.h:
--------------------------------------------------------------------------------
1 | /*
2 | 存储multiboot的信息,方便以后使用
3 | */
4 |
5 | #ifndef MULTIBOOT_H
6 | #define MULTIBOOT_H
7 | #include "common.h"
8 |
9 | typedef struct multiboot_struct{
10 | unsigned int flags; // Multiboot 的版本信息
11 | /**
12 | * 从 BIOS 获知的可用内存
13 | *
14 | * mem_lower和mem_upper分别指出了低端和高端内存的大小,单位是K。
15 | * 低端内存的首地址是0,高端内存的首地址是1M。
16 | * 低端内存的最大可能值是640K。
17 | * 高端内存的最大可能值是最大值减去1M。但并不保证是这个值。
18 | */
19 | unsigned int mem_lower;
20 | unsigned int mem_upper;
21 |
22 | unsigned int boot_device; // 指出引导程序从哪个BIOS磁盘设备载入的OS映像
23 | unsigned int cmdline; // 内核命令行
24 | unsigned int mods_count; // boot 模块列表
25 | unsigned int mods_addr;
26 |
27 | /**
28 | * ELF 格式内核映像的section头表。
29 | * 包括每项的大小、一共有几项以及作为名字索引的字符串表。
30 | */
31 | unsigned int num;
32 | unsigned int size;
33 | unsigned int addr;
34 | unsigned int shndx;
35 |
36 | /**
37 | * 以下两项指出保存由BIOS提供的内存分布的缓冲区的地址和长度
38 | * mmap_addr是缓冲区的地址,mmap_length是缓冲区的总大小
39 | * 缓冲区由一个或者多个下面的 mmap_entry_t 组成
40 | */
41 | unsigned int mmap_length;
42 | unsigned int mmap_addr;
43 |
44 | unsigned int drives_length; // 指出第一个驱动器结构的物理地址
45 | unsigned int drives_addr; // 指出第一个驱动器这个结构的大小
46 | unsigned int config_table; // ROM 配置表
47 | unsigned int boot_loader_name; // boot loader 的名字
48 | unsigned int apm_table; // APM 表
49 | unsigned int vbe_control_info;
50 | unsigned int vbe_mode_info;
51 | unsigned int vbe_mode;
52 | unsigned int vbe_interface_seg;
53 | unsigned int vbe_interface_off;
54 | unsigned int vbe_interface_len;
55 | } __attribute__((packed)) multiboot_struct;
56 |
57 | /**
58 | * size是相关结构的大小,单位是字节,它可能大于最小值20
59 | * base_addr_low是启动地址的低32位,base_addr_high是高32位,启动地址总共有64位
60 | * length_low是内存区域大小的低32位,length_high是内存区域大小的高32位,总共是64位
61 | * type是相应地址区间的类型,1代表可用RAM,所有其它的值代表保留区域
62 | */
63 | typedef struct mmap_entry_t {
64 | unsigned int size; // 留意 size 是不含 size 自身变量的大小
65 | //因为可能要包括内存外的地址,所以base_addr和length都为64位
66 | unsigned int base_addr_low;
67 | unsigned int base_addr_high;
68 | unsigned int length_low;
69 | unsigned int length_high;
70 | //type 是指内存是位于ram中,还是其他地方
71 | unsigned int type;
72 | } __attribute__((packed)) mmap_entry_t;
73 | //使用extern是因为这个变量整个工程中,只能有一个,
74 | //如果不加,每个链接这个头文件的c程序都有有自己的multiboot
75 | extern multiboot_struct *glb_mboot_ptr_tmp;
76 | extern multiboot_struct *glb_mboot_ptr;
77 | #endif
78 |
--------------------------------------------------------------------------------
/include/sched.h:
--------------------------------------------------------------------------------
1 | #ifndef SCHED_H
2 | #define SCHED_H
3 |
4 | #include "common.h"
5 | #include "memory_manager.h"
6 | #include "virtual_memory.h"
7 | #include "memory_pool.h"
8 |
9 | #define TASK_RUNNING 0 //任务可以被调度成为当前任务,就绪状态
10 | #define TASK_SLEEP 1 //睡眠,或叫做阻塞
11 | #define TASK_ZIMBIE 2 //任务去世,但id未注销
12 | #define TASK_STOPPED 4 //用于调试
13 | /*
14 | 每个任务都有一个PCB结构和一片用于系统空间堆栈的存储空间
15 | 一共两个STACK_SIZE=2*页表=2*4KB
16 | PCB放在低端,堆栈则是从高往下
17 | */
18 | typedef struct context{//任务的上下文
19 | unsigned int esp;
20 | unsigned int ebp;
21 | unsigned int ebx;
22 | unsigned int esi;
23 | unsigned int edi;
24 | unsigned int eflags;
25 | } context_t;
26 |
27 | typedef struct task_struct{
28 | //TCB,任务控制块
29 | unsigned int pid;//任务号
30 | unsigned char state;//状态
31 | context_t context;//上下文
32 | page_dir_entry *mm;//页目录项起始地址,轻量级进程用不到
33 | struct task_struct *next;//下一个任务
34 | } task_t;
35 |
36 | extern unsigned int kern_stack_top;//初始主任务的堆栈顶
37 | extern unsigned int current_pid; //当前运行的任务号
38 | extern task_t *running_task_queue;//就绪任务队列
39 | extern task_t *sleep_task_queue;//阻塞任务队列
40 | extern task_t *current_task;//当前运行任务
41 | int kernel_thread(int (*fn)(void*));
42 | void kthread_exit();
43 |
44 | void init_schedule();//初始化调度
45 | void schedule();//调度
46 | void task_switch(context_t *prev, context_t *next);//任务切换
47 | //
48 | int fork();
49 | int getpid();
50 | #endif
51 |
--------------------------------------------------------------------------------
/include/syscall.h:
--------------------------------------------------------------------------------
1 | #ifndef SYSCALL_H
2 | #define SYSCALL_H
3 | #include "common.h"
4 | #include "monitor.h"
5 |
6 | /////定义一个TSS段
7 | typedef struct tss_struct{
8 | unsigned int prev_tss; // 上一个tss,硬件任务切换时会用到tss链
9 | unsigned int esp0; // 内核模式下的堆栈指针
10 | unsigned int ss0; // 内核模式下的栈段地址
11 | unsigned int esp1; //
12 | unsigned int ss1; //ring1和2都没有用
13 | unsigned int esp2; //
14 | unsigned int ss2;
15 | unsigned int cr3;
16 | unsigned int eip;
17 | unsigned int eflags;
18 | unsigned int eax;
19 | unsigned int ecx;
20 | unsigned int edx;
21 | unsigned int ebx;
22 | unsigned int esp;
23 | unsigned int ebp;
24 | unsigned int esi;
25 | unsigned int edi;
26 | unsigned int es; // The value to load into ES when we change to kernel mode.
27 | unsigned int cs; // The value to load into CS when we change to kernel mode.
28 | unsigned int ss; // The value to load into SS when we change to kernel mode.
29 | unsigned int ds; // The value to load into DS when we change to kernel mode.
30 | unsigned int fs; // The value to load into FS when we change to kernel mode.
31 | unsigned int gs; // The value to load into GS when we change to kernel mode.
32 | unsigned int ldt; // Unused...
33 | unsigned short trap;
34 | unsigned short iomap_base;
35 | } __attribute__((packed));
36 |
37 | typedef struct tss_struct tss_t;
38 |
39 | void switch_usermode();//切换到用户模式
40 | //extern void tss_flush();//载入tss段,在gdt.s中实现
41 | void init_syscall();//初始化系统调用
42 | void syscall_printf(char*,unsigned int);
43 | void set_kernel_stack(unsigned int stack);
44 | #endif
45 |
--------------------------------------------------------------------------------
/include/timer.h:
--------------------------------------------------------------------------------
1 | #ifndef TIMER_H
2 | #define TIMER_H
3 |
4 | #include "common.h"
5 | void init_timer(unsigned int frequency);
6 |
7 | #endif
8 |
--------------------------------------------------------------------------------
/include/virtual_memory.h:
--------------------------------------------------------------------------------
1 | #ifndef VIRTUAL_MEMORY_H
2 | #define VIRTUAL_MEMORY_H
3 |
4 | #include "common.h"
5 | #include "memory_manager.h"
6 | #include "descriptor_tables.h"
7 | //内核在0xC0000000后地址运行
8 | #define KERNEL_OFFSET 0xC0000000
9 | /*
10 | 以下是页表项结构,32bit,放在页表中,用来指向实际的地址
11 | 31 12 | 11 9 | 8 7 | 6 | 5 | 4 3 | 2 | 1 | 0
12 | frame address | AVIAL | RSVD| D | A | RSVD|U/S|R/W| P
13 |
14 | 说明:
15 | P:如果当此页表在内存时,P = 1;
16 | R/W:如果=1,则可写,=0不可写
17 | U/S:如果=1,用户模式下的页面,=0,内核模式下的页面。
18 | (用户进程是不能访问内核模式下的页面的,需要系统调用)
19 | RSVD:保留
20 | A:CPU设置的,页面可行位
21 | D:传说中的脏位,用来指明内存中的数据是否被修改过(是否和磁盘中的数据
22 | 一致),对应不同的页表修改机制,脏位有不同的用法。
23 | frame address:指向物理内存地址
24 | */
25 | #define PAGE_P 0x1
26 | #define PAGE_RW 0x2
27 | #define PAGE_US 0x4
28 | //虚拟分页的大小任然是4KB
29 | //#define VM_PAGE_SIZE 0x1000//已经在memory_manger.h中定义
30 | //对齐4KB
31 | #define PAGE_MASK 0xFFFFF000
32 | /*
33 | 定义页目录项,页表项的数据类型
34 | ~~说是数据类型,起始不就是一个32位空间罢了
35 | */
36 | typedef unsigned int page_dir_entry;
37 | typedef unsigned int page_table_entry;
38 | /*
39 | 因为只能用一个页(4kb)来存储页目录,页表,
40 | 所以我们可以求出一个页内的页目录项数,和页表项数
41 | */
42 | #define PDE_NUM (PAGE_SIZE/sizeof(unsigned int))
43 | #define PTE_NUM (PAGE_SIZE/sizeof(unsigned int))
44 | //映射512MB需要128个页表,
45 | //因为一个页面(保存这页表)能存放4KB/4B=1K个页表项,对应出去是1K×4KB=4MB的内存
46 | //所以512MB需要128个这种页面,实际上页目录能存1K个页表,但这里只用到128个~~
47 | //注意:这里的只管理512MB指的是物理内存,但线性逻辑空间有
48 | //4GB
49 | #define PAGE_DIR_ENTRY_NUM 128
50 | extern page_dir_entry pde_kern[PDE_NUM];//内核页目录数组
51 | /*
52 | 一下宏函数用于获取目录项号,页表项号,和偏移地址
53 | */
54 | #define GET_PDE_NUM(x) (((x) >> 22) & 0x3FF)
55 | #define GET_PTE_NUM(x) (((x) >> 12) & 0x3FF)
56 | #define GET_OFFSET(x) ((x) & 0xFFF)
57 |
58 | //************函数定义×××××××××//
59 |
60 | void init_virtual_memory();
61 | void switch_page_dir();//切换页目录(页目录放在CR3)
62 | //将虚拟地址映射到物理地址
63 | void map(page_dir_entry *pde_now,unsigned int virtual_addr,unsigned int physics_addr,unsigned int flags);
64 | //取消对虚拟地址的映射
65 | void unmap(page_dir_entry *pde_now,unsigned int virtual_addr);
66 | //如果虚拟地址已经映射,返回1
67 | //如果physics_addr不为空指针,则把物理地址写入physics_addr
68 | unsigned int get_mapping(page_dir_entry *pde_now,unsigned int virtual_addr,unsigned int *physics_addr);
69 | void page_fault(registers_t *regs);
70 | //切换进程未实现,暂时用不到
71 | page_dir_entry *clone_dir(page_dir_entry*);//复制页目录项
72 | #endif
73 |
--------------------------------------------------------------------------------
/init/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | 主程序
3 | */
4 | #include "common.h"
5 | #include "memory_manager.h"
6 | #include "virtual_memory.h"
7 | #include "memory_pool.h"
8 | #include "fs.h"
9 | #include "initrd.h"
10 | #include "sched.h"
11 | #include "syscall.h"
12 | #include "keyboard.h"
13 | extern unsigned int placement_address;
14 | //extern unsigned int kern_stack_top;
15 | int main();
16 | //void stest();
17 | multiboot_struct *glb_mboot_ptr;//切换到分页后要用的multiboot指针
18 | char kern_stack[STACK_SIZE];
19 | //建立临时页目录项,页表项,用来指向两个页
20 | __attribute__((section(".init.data"))) page_dir_entry *pde_tmp = (page_dir_entry *)0x1000;
21 | __attribute__((section(".init.data"))) page_dir_entry *pte_low = (page_dir_entry *)0x2000;
22 | __attribute__((section(".init.data"))) page_dir_entry *pte_high = (page_dir_entry *)0x3000;
23 |
24 | __attribute__((section(".init.text"))) void entry()
25 | {
26 | //init_descriptor_tables();
27 | pde_tmp[0] = (unsigned int)pte_low|PAGE_P|PAGE_RW;
28 | pde_tmp[GET_PDE_NUM(KERNEL_OFFSET)]=(unsigned int)pte_high|PAGE_P|PAGE_RW;
29 | int i;
30 | //4KB/4B=1024
31 | for(i = 0; i<1024; i++)
32 | {
33 | pte_low[i] = (i<<12) | PAGE_P | PAGE_RW;
34 | }
35 | for(i = 0; i<1024; i++)
36 | {
37 | pte_high[i] = (i<<12) |PAGE_P | PAGE_RW;
38 | }
39 | //设置页目录的地址,向CR3赋值
40 | asm volatile ("mov %0, %%cr3" : : "r" (pde_tmp));
41 | //设置CR0的PG位为1,PG位是CR0的最高位
42 | unsigned int cr0=0;
43 | asm volatile ("mov %%cr0, %0" : "=r" (cr0));
44 | cr0|=0x80000000;
45 | asm volatile ("mov %0, %%cr0" : : "r" (cr0));
46 | //切换内核栈
47 | kern_stack_top=((unsigned int)kern_stack+STACK_SIZE) & 0xFFFFFFF0;
48 | asm volatile ("mov %0, %%esp\n\t"
49 | "xor %%ebp, %%ebp" : : "r" (kern_stack_top));
50 | glb_mboot_ptr=glb_mboot_ptr_tmp + KERNEL_OFFSET;
51 | //glb_mboot_ptr=glb_mboot_ptr_tmp;
52 | main();
53 | }
54 |
55 | int main()
56 | {
57 | init_descriptor_tables();
58 | monitor_clear();
59 | printf("welcome to batboy-mini-os!\n",0);
60 | printf("You can use 'help' to find more command!\n",0);
61 |
62 | glb_mboot_ptr->flags|=0x8;
63 | unsigned int initrd_location = *((unsigned int*)glb_mboot_ptr->mods_addr);
64 | unsigned int initrd_end = *(unsigned int*)(glb_mboot_ptr->mods_addr+4);
65 | //placement_address = initrd_end;
66 | // asm volatile ("sti");
67 | // print_memory();
68 | //asm volatile ("int $0x3");
69 |
70 | init_memory();
71 | init_virtual_memory();
72 | init_pool();
73 | fs_root = initialise_initrd(initrd_location+KERNEL_OFFSET);
74 | asm volatile ("sti");
75 | init_schedule();
76 | // printf("--------------systerm call test-------------------\n",0);
77 | init_syscall();
78 | // switch_usermode();
79 | // asm volatile ("sti");
80 | // syscall_printf("I will not give up my hope!\n",0);
81 |
82 | init_keyboard();
83 | while(1)
84 | {
85 | asm volatile ("hlt");
86 | }
87 | }
88 |
89 |
--------------------------------------------------------------------------------
/initrd.img:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luohaha/batboy-mini-kernel/cf2661e47c5e8ddac53a37637c5a695525e94452/initrd.img
--------------------------------------------------------------------------------
/kernels/mm_clone.s:
--------------------------------------------------------------------------------
1 | [GLOBAL read_eip]
2 | read_eip:
3 | pop eax ; Get the return address
4 | jmp eax ; Return. Can't use RET because return
5 | ; address popped off the stack.
6 |
7 | [GLOBAL copy_page]
8 | copy_page:
9 | push ebx ; According to __cdecl, we must preserve the contents of EBX.
10 | pushf ; push EFLAGS, so we can pop it and reenable interrupts
11 | ; later, if they were enabled anyway.
12 | cli ; Disable interrupts, so we aren't interrupted.
13 | ; Load these in BEFORE we disable paging!
14 | mov ebx, [esp+12] ; Source address
15 | mov ecx, [esp+16] ; Destination address
16 |
17 | mov edx, cr0 ; Get the control register...
18 | and edx, 0x7fffffff ; and...
19 | mov cr0, edx ; Disable paging.
20 |
21 | mov edx, 1024 ; 1024*4bytes = 4096 bytes
22 |
23 | .loop:
24 | mov eax, [ebx] ; Get the word at the source address
25 | mov [ecx], eax ; Store it at the dest address
26 | add ebx, 4 ; Source address += sizeof(word)
27 | add ecx, 4 ; Dest address += sizeof(word)
28 | dec edx ; One less word to do
29 | jnz .loop
30 |
31 | mov edx, cr0 ; Get the control register again
32 | or edx, 0x80000000 ; and...
33 | mov cr0, edx ; Enable paging.
34 |
35 | popf ; Pop EFLAGS back.
36 | pop ebx ; Get the original value of EBX back.
37 | ret
38 |
39 |
--------------------------------------------------------------------------------
/kernels/process.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 | #include "sched.h"
3 |
4 | int kernel_thread(int (*fn)(void*))
5 | {
6 | task_t *new_task = (task_t *)kmalloc(STACK_SIZE);
7 | memset(new_task,0,sizeof(task_t));
8 | new_task->pid=current_pid++;
9 | new_task->state=TASK_RUNNING;
10 | new_task->mm=0;
11 | unsigned int *new_top = (unsigned int*)((unsigned int)new_task+STACK_SIZE);
12 | *(--new_top)=(unsigned int)kthread_exit;
13 | *(--new_top)=(unsigned int)fn;
14 | new_task->context.eflags=0x200;
15 | new_task->context.esp=(unsigned int)new_task+STACK_SIZE-2*sizeof(unsigned int);
16 | new_task->next=running_task_queue;
17 | task_t *point=running_task_queue;
18 | while(point->next!=running_task_queue)
19 | point=point->next;
20 | point->next=new_task;
21 | return new_task->pid;//返回新任务的id
22 | }
23 | ///////////////
24 | //////////////fork()未完成,任务切换有问题,切换后系统会崩溃
25 | int fork()
26 | {
27 | asm volatile("cli");
28 | task_t *new_task = (task_t *)kmalloc(STACK_SIZE);
29 | memset(new_task,0,sizeof(task_t));
30 | //新建页目录
31 | // page_dir_entry *newdir = clone_dir(current_task->mm);
32 | new_task->pid=current_pid++;
33 | new_task->state=TASK_RUNNING;
34 | //页目录赋值
35 | // new_task->mm=newdir;
36 | new_task->mm=current_task->mm;
37 | new_task->context=current_task->context;
38 | new_task->next=running_task_queue;
39 | task_t *point=running_task_queue;
40 | while(point->next!=running_task_queue)
41 | point=point->next;
42 | point->next=new_task;
43 | // asm volatile ("sti");
44 | return new_task->pid;//返回新任务的id
45 |
46 | }
47 | void kthread_exit()
48 | {
49 | //把当前任务从running_task_queue队列中移除
50 | task_t *point=running_task_queue;
51 | while(point->next!=current_task)
52 | point=point->next;
53 | point->next=current_task->next;
54 | //把完成的任务放入sleep_task_queue队列中,准备回收内存空间
55 | if(sleep_task_queue==0)
56 | sleep_task_queue=current_task;
57 | else
58 | {
59 | kfree(sleep_task_queue);
60 | sleep_task_queue=current_task;
61 | }
62 | //这里不能提前函数返回,因为堆栈中已经没有数,提前退出会出现访问页
63 | //错误
64 | while(1);
65 | }
66 |
--------------------------------------------------------------------------------
/kernels/schedule.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 | #include "sched.h"
3 | #include "memory_manager.h"
4 | #include "virtual_memory.h"
5 | #include "memory_pool.h"
6 | unsigned int kern_stack_top;//初始主任务的堆栈顶
7 | unsigned int current_pid=0; //当前运行的任务号
8 | task_t *running_task_queue=0;//就绪任务队列
9 | task_t *sleep_task_queue=0;//阻塞任务队列
10 | task_t *current_task=0;//当前运行任务
11 | void init_schedule()
12 | {
13 | current_task = (task_t*)(kern_stack_top-STACK_SIZE);
14 | current_task->pid=current_pid++;
15 | current_task->state=TASK_RUNNING;
16 | //current_task->mm=(unsigned int)pde_kern-KERNEL_OFFSET;
17 | //未实现进程,所以还用不到独立内存空间
18 | current_task->mm=0;
19 | current_task->next=current_task;//只有一个任务
20 | running_task_queue=current_task;
21 | }
22 |
23 | void schedule()
24 | {
25 | if(current_task&¤t_task->next!=current_task)
26 | // if(current_task)
27 | {
28 | task_t *prev_task = current_task;
29 | current_task=current_task->next;
30 | task_switch(&(prev_task->context),&(current_task->context));
31 | // switch_page_dir(current_task->mm);
32 | // 未实现进程,不用切换内存空间
33 | }
34 | }
35 |
36 | int getpid()
37 | {
38 | return current_task->pid;
39 | }
40 |
--------------------------------------------------------------------------------
/kernels/syscall.c:
--------------------------------------------------------------------------------
1 | /*系统调用部分未完成!!!
2 | bug: switch_usermode()函数执行时,会产生13号中断,就是常规保护错误
3 |
4 | */
5 | #include "syscall.h"
6 | #include "monitor.h"
7 | #include "descriptor_tables.h"
8 | #include "sched.h"
9 | #include "memory_manager.h"
10 | #include "virtual_memory.h"
11 | #include "memory_pool.h"
12 | extern task_t *current_task;//当前运行任务
13 | extern unsigned int kern_stack_top;//初始主任务的堆栈顶
14 |
15 | static void syscall_handler(registers_t *regs);
16 | static void *syscall_function[1]={
17 | &printf,
18 | };
19 | unsigned int function_number=1;
20 | void switch_usermode()
21 | //切换到用户模式,用户模式的代码段为0x18,在将低两位(RPL)全部置一,0x18|0x3=0x1b
22 | //同理数据段为0x20,然后RPL置一,0x20|0x3=0x23
23 | //bug: 嵌入at&t汇编在执行时会产出13号中断
24 | //按理来说,iret后eip,cs和eflags应该被弹出,然后赋值.接着在执行label 1 的下面程序(已经进入user模式),
25 | //但是不知为什么,会出现13号中断错误(常规保护错误).
26 | //date: 2015-02-09
27 | {
28 | //set_kernel_stack(kern_stack_top);
29 | set_kernel_stack((unsigned int)current_task+STACK_SIZE);
30 | asm volatile(" \
31 | cli; \
32 | mov $0x23, %ax; \
33 | mov %ax, %ds; \
34 | mov %ax, %es; \
35 | mov %ax, %fs; \
36 | mov %ax, %gs; \
37 | \
38 | movl %esp, %eax; \
39 | pushl $0x23; \
40 | pushl %eax; \
41 | pushf; \
42 | popl %eax; \
43 | orl $0x200, %eax; \
44 | pushl %eax; \
45 | pushl $0x1B; \
46 | pushl $1f; \
47 | iret; \
48 | 1: \
49 | ");
50 | // asm volatile(" \
51 | cli; \
52 | mov $0x23, %ax; \
53 | mov %ax, %ds; \
54 | mov %ax, %es; \
55 | mov %ax, %fs; \
56 | mov %ax, %gs; \
57 | \
58 | mov %esp, %eax; \
59 | mov $0x23, %ss; \
60 | movl %eax, %esp; \
61 | pushf; \
62 | popl %eax; \
63 | orl $0x200, %eax; \
64 | pushl %eax; \
65 | popf; \
66 | mov $0x1B, %cs; \
67 | movl $1f, %eip; \
68 | ret; \
69 | 1: \
70 | ");
71 | }
72 |
73 |
74 | void init_syscall()
75 | {
76 | //注册系统调用到中断128号(模仿linux)
77 | register_int_handler(128,&syscall_handler);
78 | }
79 |
80 | void syscall_handler(registers_t *regs)
81 | {
82 | //if(regs->eax>0)
83 | return;
84 | void *now_function=syscall_function[regs->eax];
85 | //用汇编语言实现1.压入可能用到的参数.2.调用函数.3.返回返回值~~
86 | int retval;//返回值
87 | asm volatile ("\
88 | push %1;\
89 | push %2;\
90 | push %3;\
91 | push %4;\
92 | push %5;\
93 | call *%6;\
94 | pop %%ebx;\
95 | pop %%ebx;\
96 | pop %%ebx;\
97 | pop %%ebx;\
98 | pop %%ebx;\
99 | ":"=a"(retval):"r" (regs->edi),"r" (regs->esi),"r" (regs->edx),"r" (regs->ecx),"r" (regs->ebx),"r" (now_function));
100 | regs->eax=retval;
101 | }
102 | void syscall_printf(char *s,unsigned int num)
103 | {
104 | int rt;
105 | int he=0;
106 | asm volatile ("int $0x80" :"=a" (rt): "0" (he),"b" ((int)s),"c" ((int)num));
107 | // asm volatile("int $0x80;");
108 | return;
109 | }
110 |
--------------------------------------------------------------------------------
/kernels/task_switch.s:
--------------------------------------------------------------------------------
1 | [GLOBAL task_switch]
2 |
3 | task_switch:
4 | mov eax, [esp+4] ;源任务上下文地址
5 | mov [eax+0], esp ;
6 | mov [eax+4], ebp
7 | mov [eax+8], ebx
8 | mov [eax+12], esi
9 | mov [eax+16], edi
10 | pushf ;push eflags
11 | pop ecx
12 | mov [eax+20], ecx
13 |
14 | mov eax, [esp+8] ;新任务
15 | mov esp, [eax+0]
16 | mov ebp, [eax+4]
17 | mov ebx, [eax+8]
18 | mov esi, [eax+12]
19 | mov edi, [eax+16]
20 | mov eax, [eax+20]
21 | push eax
22 | popf ;将堆栈顶的数值(eflags)弹出赋值
23 |
24 | ret
25 |
--------------------------------------------------------------------------------
/lib/common.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 |
3 | // Write a byte out to the specified port.
4 | void outb(unsigned short port, unsigned char value)
5 | {
6 | asm volatile ("outb %1, %0" : : "dN" (port), "a" (value));
7 | }
8 |
9 | unsigned char inb(unsigned short port)
10 | {
11 | unsigned char ret;
12 | asm volatile("inb %1, %0" : "=a" (ret) : "dN" (port));
13 | return ret;
14 | }
15 |
16 | unsigned short inw(unsigned short port)
17 | {
18 | unsigned short ret;
19 | asm volatile ("inw %1, %0" : "=a" (ret) : "dN" (port));
20 | return ret;
21 | }
22 |
--------------------------------------------------------------------------------
/lib/keyboard.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 | #include "memory_manager.h"
3 | #include "virtual_memory.h"
4 | #include "memory_pool.h"
5 | #include "fs.h"
6 | #include "initrd.h"
7 | #include "sched.h"
8 | #include "syscall.h"
9 | #include "keyboard.h"
10 | #include "monitor.h"
11 | int haha=0;
12 | extern fs_node_t *fs_root; // The root of the filesystem.
13 | static void keyboard_handler();//键盘处理函数
14 | static void exe_cmd(char *todo);//执行命令行函数
15 | static char keytable[0x54] = {0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0x08, '\t','Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', '\n', 0, 'A', 'S','D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', 0,0, '\\', 'Z', 'X', 'C', 'V','B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1','2', '3', '0', '.'};
16 | static int caps;//0时为小写字母
17 | //用于存储命令行
18 | static char cmd[64];
19 | //记录cmd的长度
20 | static int cmd_len;
21 | //////////******命令程序*********//////////
22 | static void show_memory();
23 | static void help();
24 | static void show_pool();
25 | static void show_file();
26 | static void show_task();
27 | /////////////////多任务的展示函数
28 | void stest()
29 | {
30 | unsigned int i=0;
31 | while(1)
32 | {
33 | i++;
34 | if(haha==0)
35 | {
36 | printf("a",0);
37 | haha=1;
38 | }
39 | if(i==0x1000000)
40 | break;
41 | }
42 | return ;
43 | }
44 | void stest2()
45 | {
46 | unsigned int i=0;
47 | while(1)
48 | {
49 | i++;
50 | if(haha==1)
51 | {
52 | printf("c",0);
53 | haha=0;
54 | }
55 | if(i==0x1000000)
56 | break;
57 | }
58 | return ;
59 | }
60 | /////////////////////////////////////
61 | void init_keyboard()
62 | //键盘初始化,将键盘处理函数注册到
63 | //IRQ1,33号中断
64 | {
65 | printf("batboy$$$>>>>",0);
66 | register_int_handler(33,keyboard_handler);
67 | caps=0;
68 | cmd_len=0;
69 | }
70 | void keyboard_handler()
71 | {
72 | unsigned char ret;
73 | ret = inb(0x60);//读入键盘输入
74 | if(ret&0x80)
75 | //松开按键时的编码
76 | {
77 | if(ret==0xba)
78 | //caps lock键
79 | {
80 | caps^=1;
81 | }
82 |
83 | }
84 | else
85 | //按下按键时的编码
86 | {
87 | if(caps==0&&keytable[ret]>=65&&keytable[ret]<=90)
88 | {
89 | monitor_put(keytable[ret]+32);
90 | }
91 | else
92 | monitor_put(keytable[ret]);
93 | //执行命令行
94 | if(keytable[ret]!='\n')
95 | cmd[cmd_len++]=keytable[ret];
96 | else
97 | {
98 | exe_cmd(cmd);
99 | printf("\n",0);
100 | cmd_len=0;
101 | cmd[cmd_len]=' ';
102 | printf("batboy$$$>>>>",0);
103 | }
104 | }
105 | }
106 | void exe_cmd(char *todo)
107 | {
108 | switch(todo[0])
109 | {
110 | case 'M':
111 | show_memory();
112 | break;
113 | case 'H':
114 | help();
115 | break;
116 | case 'P':
117 | show_pool();
118 | break;
119 | case 'F':
120 | show_file();
121 | break;
122 | case 'T':
123 | show_task();
124 | // printf('\n',0);
125 | break;
126 | default:
127 | printf("wrong command!\n",0);
128 | printf("please input 'help' for help\n",0);
129 | break;
130 | }
131 | }
132 | void show_memory()
133 | {
134 | printf("\n--------------memory-------------------\n",0);
135 | printf("code start: ",0);
136 | printf("%h",kern_start);
137 | printf("\n",0);
138 | printf("code end: ",0);
139 | printf("%h",kern_end);
140 | printf("\n",0);
141 | printf("code's memory use(KB): ",0);
142 | printf("%h",(kern_end-kern_start+1023)/1024);
143 | printf("\n",0);
144 | }
145 | void help()
146 | {
147 | printf("------------command list---------------\n",0);
148 | printf("memory: show memory use\n",0);
149 | printf("pool : show kmalloc and kfree\n",0);
150 | printf("task : show multi-task, print 'a' and 'c' at the same time\n",0);
151 | printf("file : show file write and read\n",0);
152 | printf("\n",0);
153 | }
154 | void show_pool()
155 | {
156 | printf("\n--------------memory pool---------------------\n",0);
157 | // printf("now usefull pages is: ",0);
158 | // printf("%d",page_count);
159 | // printf("\n",0);
160 | /* int i;
161 | for(i=0;i<4;i++)
162 | {
163 | printf("0x",0);
164 | printf("%h",memory_alloc());
165 | printf("\n",0);
166 | }*/
167 | pool_test();
168 | printf("\n",0);
169 | }
170 | void show_file()
171 | {
172 | printf("\n--------------read file----------------------\n",0);
173 | int i = 0;
174 | struct dirent *node = 0;
175 | // printf("%h",(unsigned int)glb_mboot_ptr->mods_count);
176 | // printf("loaded\n",0);
177 | while ( (node = readdir_fs(fs_root, i)) != 0)
178 | //读出根目录下的所有文件,从0号开始
179 | {
180 | printf("file: ",0);
181 | printf(node->name,0);
182 | fs_node_t *fsnode = finddir_fs(fs_root, node->name);
183 |
184 | if ((fsnode->flags&0x7) == FS_DIRECTORY)
185 | {
186 | printf("\n\t(directory)\n",0);
187 | }
188 | else
189 | {
190 | printf("\n\t contents: ",0);
191 | char buf[256];
192 | char *change="I will not give up hope, and i have to try!\n yes you can!";
193 | unsigned int zs = write_fs(fsnode,0,256,change);
194 | unsigned int sz = read_fs(fsnode, 0, 256, buf);
195 | printf("write size: ",0);
196 | printf("%d",zs);
197 | printf("read size: ",0);
198 | printf("%d",sz);
199 | printf("\n",0);
200 | int j;
201 | for (j = 0; j < sz+15; j++)
202 | monitor_put(buf[j]);
203 |
204 | printf("\n",0);
205 | }
206 | i++;
207 | }
208 |
209 | }
210 | void show_task()
211 | {
212 | printf("---------------kernel thread test-------------------\n",0);
213 |
214 | init_timer(200);
215 | asm volatile ("sti");
216 | kernel_thread(stest);
217 | kernel_thread(stest2);
218 |
219 | }
220 |
--------------------------------------------------------------------------------
/lib/monitor.c:
--------------------------------------------------------------------------------
1 | #include "monitor.h"
2 | #include "virtual_memory.h"
3 | unsigned short cursor_x=0;
4 | unsigned short cursor_y=0;
5 | unsigned short *video_memory=(unsigned short*)(0xB8000+KERNEL_OFFSET);
6 | //unsigned short *video_memory=(unsigned short*)(0xB8000);
7 | static void move_cursor()
8 | //刷新光标位置
9 | {
10 | /*
11 | port(0x3D4)+command(14)=>发高地址=>发给0x3D5
12 | command(15)=>发低地址
13 | */
14 | unsigned short location=cursor_y*80+cursor_x;
15 | outb(0x3D4,14);
16 | outb(0x3D5,location>>8);
17 | outb(0x3D4,15);
18 | outb(0x3D5,location);
19 | }
20 | static void scroll()
21 | {
22 | unsigned char color=(0xf<<4)|(0x4&0x0f);
23 | unsigned short blank=0x20|(color<<8);//空格
24 | if(cursor_y>=25)
25 | //当到达底部时,向上滚动
26 | {
27 | int i;
28 | for(i=0;i<24*80;i++)
29 | {
30 | video_memory[i]=video_memory[i+80];
31 | }
32 | for(i=24*80;i<25*80;i++)
33 | {
34 | video_memory[i]=blank;
35 | }
36 | cursor_y=24;
37 | }
38 | }
39 | void monitor_put(char c)
40 | {
41 | unsigned char backcolor=0xf;//背景色为白色
42 | unsigned char forecolor=0x4;//背景色为红色
43 | unsigned short color=(backcolor<<4)|(forecolor&0x0f);
44 | unsigned short *location;//要存放光标所在处的地址
45 | if(c==0x08&&cursor_x>13)
46 | {
47 | //退格键
48 | cursor_x--;
49 | location=video_memory+(cursor_y*80+cursor_x);//光标处地址
50 | char ttmp=' ';
51 | *location=ttmp|(color<<8);//该显示的值
52 |
53 | }
54 | else if(c==0x09)
55 | {
56 | //tab键
57 | cursor_x=(cursor_x+8)&~7;
58 | }
59 | else if(c=='\r')
60 | {
61 | cursor_x=0;
62 | }
63 | else if(c=='\n')
64 | {
65 | cursor_x=0;
66 | cursor_y++;
67 | }
68 | else if(c>=' ')
69 | {
70 | location=video_memory+(cursor_y*80+cursor_x);//光标处地址
71 | *location=c|(color<<8);//该显示的值
72 | cursor_x++;
73 | }
74 |
75 | if(cursor_x>=80)
76 | {
77 | cursor_x=0;
78 | cursor_y++;
79 | }
80 | scroll();
81 | move_cursor();//刷新显示
82 | }
83 | void monitor_clear()
84 | {
85 | unsigned char color=(0xf<<4)|(0x4&0x0f);
86 | unsigned short blank=0x20|(color<<8);//空格
87 | int i;
88 | for(i=0;i<25*80;i++)
89 | {
90 | video_memory[i]=blank;
91 | }
92 | cursor_x=0;
93 | cursor_y=0;
94 | move_cursor();//刷新显示
95 | }
96 | void monitor_str(char *c)
97 | {
98 | int i=0;
99 | while(c[i])
100 | {
101 | monitor_put(c[i++]);
102 | }
103 | }
104 | void monitor_hex(unsigned int c)
105 | {
106 | char str[8];
107 | int i=0;
108 | for(i=0;i<8;i++)
109 | {
110 | str[i]=(char)(c%16+48);
111 | if(str[i]>=':')
112 | str[i]+=7;
113 | c/=16;
114 | }
115 | int j;
116 | for(j=7;j>=0;j--)
117 | {
118 | monitor_put(str[j]);
119 | }
120 | }
121 | void monitor_dec(unsigned int c)
122 | {
123 | if(c==0)
124 | {
125 | monitor_put('0');
126 | }
127 | int i;
128 | unsigned int num=1000000000;
129 | int flag=0;
130 | for(i=0;i<10;i++)
131 | {
132 | int tmp=c/num;
133 | if(tmp!=0)
134 | {
135 | flag=1;
136 | char ch=(char)(tmp+48);
137 | monitor_put(ch);
138 | }
139 | else
140 | {
141 | if(flag==1)
142 | monitor_put('0');
143 | }
144 | c=c-num*tmp;
145 | num/=10;
146 | }
147 | }
148 | void printf(char *s,unsigned int c)
149 | {
150 | if(s[0]!='%')
151 | monitor_str(s);
152 | else
153 | {
154 | if(s[1]=='d')
155 | monitor_dec(c);
156 | else if(s[1]=='h')
157 | monitor_hex(c);
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/mm/memory_manager.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 | #include "memory_manager.h"
3 | #include "multiboot.h"
4 |
5 | static unsigned int page_count=0;//目前可以供使用的内存页面的数量
6 | static unsigned int page_stack[PAGE_NUMBER+1];//可用页面起始地址栈
7 |
8 |
9 | void init_memory()
10 | {
11 | unsigned int glb_addr = glb_mboot_ptr->mmap_addr;
12 | unsigned int glb_length = glb_mboot_ptr->mmap_length;
13 | mmap_entry_t *addr=(mmap_entry_t *)glb_mboot_ptr->mmap_addr;
14 | for(;(unsigned int)addrtype==1 && addr->base_addr_low==0x100000)
17 | {
18 | unsigned int usefull_addr=addr->base_addr_low + (unsigned int)(kern_end - kern_start);
19 | unsigned int max_usefull_addr=addr->base_addr_low + addr->length_low;
20 | for(;usefull_addr0)
39 | return page_stack[--page_count];
40 | else
41 | {
42 | printf("ERROR: memory not enough\n",0);
43 | return -1;
44 | }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/mm/memory_pool.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 | #include "memory_manager.h"
3 | #include "virtual_memory.h"
4 | #include "memory_pool.h"
5 | #include "monitor.h"
6 | //用来标记按页块分配的当前最大地址,起始是POOL_BEGIN
7 | static unsigned int pool_top_page;
8 | //标记内存池当前已经分配到的位置,起始是POOL_BEGIN
9 | static unsigned int pool_top;
10 | //内存块链表头部,不使用
11 | block_head *leader;
12 | void init_pool()
13 | {
14 | pool_top_page=POOL_BEGIN;
15 | pool_top=POOL_BEGIN;
16 | //新建一个长度为PAGE_SIZE的内存块
17 | //不试用,只是作为链表的头部,大方吧
18 | leader=(block_head *)pool_top;
19 | unsigned int newpage=memory_alloc();
20 | map(pde_kern,(unsigned int)leader,newpage,PAGE_P|PAGE_RW);
21 | leader->length=sizeof(block_head);
22 | leader->used=1;
23 | leader->pre=0;
24 | leader->next=0;
25 | pool_top_page=POOL_BEGIN+PAGE_SIZE;
26 | pool_top=POOL_BEGIN+leader->length;
27 | }
28 | void* kmalloc(unsigned int length)
29 | //申请内存函数,返回可用空间的首地址
30 | {
31 | block_head *point=leader;//查找可用块的指针
32 | block_head *tmppre=point;//用来暂存point的上一个
33 | while(point!=0)
34 | {
35 | //if(point->used==0&&point->length>=sizeof(block_head)*2+length)
36 | if(point->used==0&&point->length>=length+sizeof(block_head))
37 | //如果能找到一个合适内存块
38 | {
39 | if(point->length>=sizeof(block_head)*2+length)
40 | {
41 | point->used=1;
42 | unsigned int tmp=point->length;
43 | point->length=length+sizeof(block_head);
44 | //告诉cut函数,被截断后新的起点和长度,还有它的前面的block地址
45 | cut((unsigned int)point+point->length,tmp-point->length,point);
46 | return (void *)((unsigned int)point+sizeof(block_head));
47 | }
48 | else
49 | {
50 | point->used=1;
51 | return (void *)((unsigned int)point+sizeof(block_head));
52 | }
53 | }
54 | //如果不能,就继续往下找
55 | tmppre=point;
56 | point=point->next;
57 | }
58 | //如果没有现成的内存块,那要自己申请一个
59 | return alloc(length+sizeof(block_head),tmppre);
60 | }
61 | void kfree(unsigned int addr)
62 | //释放可用地址addr的内存块
63 | {
64 | block_head *old =(block_head *)(addr-sizeof(block_head));
65 | old->used=0;
66 | union_block(old);
67 | }
68 | void union_block(block_head *old)
69 | {
70 | if(old->next!=0&&old->next->used==0)
71 | //可以和后边的未使用的合并
72 | {
73 | old->length=old->length+old->next->length;
74 | if(old->next->next!=0)
75 | {
76 | old->next->next->pre=old;
77 | }
78 | old->next=old->next->next;
79 | }
80 | if(old->pre!=0&&old->pre->used==0)
81 | //和前面未使用的合并
82 | {
83 | old->pre->length=old->pre->length+old->length;
84 | if(old->next)
85 | {
86 | old->next->pre=old->pre;
87 | }
88 | old->pre->next=old->next;
89 | old=old->pre;
90 | }
91 | if(old->next==0)
92 | //回收物理内存
93 | {
94 | unsigned int tmplength=old->length;
95 | old->pre->next=0;
96 | while(pool_top-tmplength+PAGE_SIZE<=pool_top_page)
97 | {
98 | pool_top_page-=PAGE_SIZE;
99 | unsigned int page;
100 | get_mapping(pde_kern,pool_top_page,&page);//获取对应的物理地址
101 | unmap(pde_kern,pool_top_page);//解除映射
102 | memory_free(page);//回收物理内存
103 | }
104 | pool_top-=tmplength;
105 | }
106 | }
107 | void cut(unsigned int addr,unsigned int length,block_head *prev)
108 | //从地址addr开始,截下包括头部的长度length,前面的是prev
109 | {
110 | block_head *cutnew=(block_head *)addr;
111 | cutnew->used=0;
112 | cutnew->length=length;
113 | cutnew->pre=prev;
114 | cutnew->next=prev->next;
115 | prev->next->pre=cutnew;
116 | prev->next=cutnew;
117 | }
118 | void* alloc(unsigned int length,block_head *prev)
119 | //这里的length包括头部
120 | {
121 | if(pool_top+length<=pool_top_page)
122 | //当前分配的物理地址已足够使用
123 | {
124 | block_head *new=(block_head *)pool_top;
125 | new->used=1;
126 | new->length=length;
127 | new->next=0;
128 | new->pre=prev;
129 | prev->next=new;
130 | pool_top+=length;
131 | return (void *)((unsigned int)pool_top-length+sizeof(block_head));
132 |
133 | }
134 | else
135 | //需要再次分配物理内存
136 | {
137 | while(pool_top+length>pool_top_page)
138 | {
139 | unsigned int newpage=memory_alloc();
140 | map(pde_kern,pool_top_page,newpage,PAGE_P|PAGE_RW);
141 | pool_top_page+=PAGE_SIZE;
142 |
143 | }
144 | block_head *new=(block_head *)pool_top;
145 | new->used=1;
146 | new->length=length;
147 | new->next=0;
148 | new->pre=prev;
149 | prev->next=new;
150 | pool_top+=length;
151 | return (void *)((unsigned int)pool_top-length+sizeof(block_head));
152 | }
153 | }
154 | void pool_test()
155 | {
156 | void *addr=kmalloc(50);
157 | printf("\nkalloc 50B, addr: ",0);
158 | printf("%h",(unsigned int)addr);
159 | void *addr2=kmalloc(50);
160 | printf("\nkalloc 50B, addr: ",0);
161 | printf("%h",(unsigned int)addr2);
162 | void *addr4=kmalloc(50);
163 | printf("\nkalloc 50B, addr: ",0);
164 | printf("%h",(unsigned int)addr4);
165 | kfree((unsigned int)addr);
166 | printf("\nkfree 50B, addr: ",0);
167 | printf("%h",(unsigned int)addr);
168 |
169 | kfree((unsigned int)addr2);
170 | printf("\nkfree 50B, addr: ",0);
171 | printf("%h",(unsigned int)addr2);
172 | void *addr3=kmalloc(70);
173 | printf("\nkalloc 70B, addr: ",0);
174 | printf("%h",(unsigned int)addr3);
175 | kfree((unsigned int)addr3);
176 | printf("\nkfree 70B, addr: ",0);
177 | printf("%h",(unsigned int)addr3);
178 | }
179 |
--------------------------------------------------------------------------------
/mm/memory_tool.c:
--------------------------------------------------------------------------------
1 | #include "memory.h"
2 |
3 | void memset(void *dest, unsigned char val, unsigned int len)
4 | {
5 | unsigned char *dst = (unsigned char *)dest;
6 |
7 | for ( ; len != 0; len--) {
8 | *dst++ = val;
9 | }
10 | }
11 | void memcpy(unsigned char *str1,unsigned char *str2,unsigned int len)
12 | //把str2赋值给str1
13 | {
14 | while(len>0)
15 | {
16 | *str1++=*str2++;
17 | len--;
18 | }
19 | }
20 | int strcmp(unsigned char *str1,unsigned char *str2)
21 | {
22 | while(*str1&&*str2&&(*str1++==*str2++));
23 | if(*str1=='\0'&&*str2=='\0')
24 | return 0;//成功
25 | else if(*str1=='\0')
26 | return 1;
27 | else
28 | return -1;
29 | }
30 | unsigned char* strcpy(unsigned char *str1,unsigned char *str2)
31 | //将str2复制给str1,并返回str1原来的值
32 | {
33 | unsigned char *tmp=str1;
34 | while(*str2)
35 | {
36 | *str1++=*str2++;
37 | }
38 | *str1='\0';
39 | return tmp;
40 | }
41 | int strlen(unsigned char *c)
42 | {
43 | const unsigned char *eos = c;
44 | while (*eos++)
45 | ;
46 | return (eos - c - 1);
47 | }
48 |
--------------------------------------------------------------------------------
/mm/print_memory.c:
--------------------------------------------------------------------------------
1 | #include "memory_manager.h"
2 | #include "monitor.h"
3 |
4 | void print_memory()
5 | {
6 | //先找到mmap_entry的地址
7 | mmap_entry_t *mmap=(mmap_entry_t*)glb_mboot_ptr->mmap_addr;
8 | //地址分布的长度
9 | unsigned int length=glb_mboot_ptr->mmap_length;
10 | unsigned int addr =glb_mboot_ptr->mmap_addr;
11 | printf("mmap分布:\n",0);
12 | for(;(unsigned int)mmapbase_addr_high);
16 | printf("%h",mmap->base_addr_low);
17 | printf(" length: ",0);
18 | printf("%h",mmap->length_high);
19 | printf("%h",mmap->length_low);
20 | printf("\ntype: ",0);
21 | printf("%h",mmap->type);
22 | printf("\n",0);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/mm/virtual_memory.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 | #include "virtual_memory.h"
3 | #include "memory_manager.h"
4 | #include "descriptor_tables.h"
5 | #include "memory.h"
6 | #include "monitor.h"
7 | /*
8 | 1.当分页启动后,每次使用内存的地址时,系统自动转换为物理地址,也就是说,系统会默认你输入的是线性逻辑地址
9 | 2.页目录项和页表项中存的一定是物理地址,规定的~~
10 | */
11 | //定义一个全局的页目录数组,大小4KB/4B=1K
12 | page_dir_entry pde_kern[PDE_NUM] __attribute__ ((aligned(PAGE_SIZE)));
13 | //定义一个二维的页表数组,第一维对应各个页表(128个),第二维对应
14 | //每个页表中的页表项。
15 | static page_table_entry pte_kern[PAGE_DIR_ENTRY_NUM][PTE_NUM] __attribute__ ((aligned(PAGE_SIZE)));
16 | void init_virtual_memory()
17 | {
18 | int i,j;
19 | int PDE_BEGIN = GET_PDE_NUM(KERNEL_OFFSET);
20 | for(i = PDE_BEGIN, j=0 ; i < PDE_BEGIN+PAGE_DIR_ENTRY_NUM;i++,j++)
21 | {
22 | //这里需要将虚拟内存转换为物理内存
23 | pde_kern[i] = ((unsigned int) pte_kern[j]-KERNEL_OFFSET)|PAGE_P|PAGE_RW;
24 | }
25 | //对二维数组中的每个页表项赋值地址,128*1024个,
26 | //128*1024*4KB=512MB
27 | unsigned int *pte=(unsigned int *)pte_kern;
28 | for(j=1;j