├── .gitignore ├── README.md ├── chapter10 ├── keyboard │ ├── bochsrc.bxrc │ ├── device │ │ ├── console.c │ │ ├── console.h │ │ ├── ioqueue.c │ │ ├── ioqueue.h │ │ ├── keyboard.c │ │ ├── keyboard.h │ │ ├── timer.c │ │ └── timer.h │ ├── include │ │ └── boot.inc │ ├── kernel │ │ ├── debug.c │ │ ├── debug.h │ │ ├── global.h │ │ ├── init.c │ │ ├── init.h │ │ ├── interrupt.c │ │ ├── interrupt.h │ │ ├── io.h │ │ ├── kernel.asm │ │ ├── main.c │ │ ├── memory.c │ │ ├── memory.h │ │ ├── switch.asm │ │ └── thread │ │ │ ├── sync.c │ │ │ ├── sync.h │ │ │ ├── thread.c │ │ │ └── thread.h │ ├── lib │ │ ├── bitmap.c │ │ ├── bitmap.h │ │ ├── kernel │ │ │ ├── list.c │ │ │ ├── list.h │ │ │ ├── print.asm │ │ │ └── print.h │ │ ├── stdint.h │ │ ├── string.c │ │ └── string.h │ ├── loader.asm │ ├── makefile │ └── mbr.asm └── terminal_with_lock │ ├── bochsrc.bxrc │ ├── device │ ├── console.c │ ├── console.h │ ├── timer.c │ └── timer.h │ ├── include │ └── boot.inc │ ├── kernel │ ├── debug.c │ ├── debug.h │ ├── global.h │ ├── init.c │ ├── init.h │ ├── interrupt.c │ ├── interrupt.h │ ├── io.h │ ├── kernel.asm │ ├── main.c │ ├── memory.c │ ├── memory.h │ ├── switch.asm │ └── thread │ │ ├── sync.c │ │ ├── sync.h │ │ ├── thread.c │ │ └── thread.h │ ├── lib │ ├── bitmap.c │ ├── bitmap.h │ ├── kernel │ │ ├── list.c │ │ ├── list.h │ │ ├── print.asm │ │ └── print.h │ ├── stdint.h │ ├── string.c │ └── string.h │ ├── loader.asm │ ├── makefile │ └── mbr.asm ├── chapter11 ├── bochsrc.bxrc ├── device │ ├── console.c │ ├── console.h │ ├── ioqueue.c │ ├── ioqueue.h │ ├── keyboard.c │ ├── keyboard.h │ ├── timer.c │ └── timer.h ├── include │ └── boot.inc ├── kernel │ ├── debug.c │ ├── debug.h │ ├── global.h │ ├── init.c │ ├── init.h │ ├── interrupt.c │ ├── interrupt.h │ ├── io.h │ ├── kernel.asm │ ├── main.c │ ├── memory.c │ ├── memory.h │ ├── switch.asm │ └── thread │ │ ├── sync.c │ │ ├── sync.h │ │ ├── thread.c │ │ └── thread.h ├── lib │ ├── bitmap.c │ ├── bitmap.h │ ├── kernel │ │ ├── list.c │ │ ├── list.h │ │ ├── print.asm │ │ └── print.h │ ├── stdint.h │ ├── string.c │ └── string.h ├── loader.asm ├── makefile ├── mbr.asm └── user │ ├── process.c │ ├── process.h │ ├── tss.c │ └── tss.h ├── chapter3 ├── bochsrc ├── build.sh ├── clean.sh ├── include │ └── boot.inc ├── loader.asm └── mbr.asm ├── chapter4 ├── bochsrc ├── build.sh ├── clean.sh ├── include │ └── boot.inc ├── loader.asm └── mbr.asm ├── chapter5 ├── detect-memory │ ├── bochsrc │ ├── build.sh │ ├── clean.sh │ ├── include │ │ └── boot.inc │ ├── loader.asm │ └── mbr.asm ├── load-kernel │ ├── bochsrc │ ├── build.sh │ ├── clean.sh │ ├── include │ │ └── boot.inc │ ├── kernel │ │ └── main.c │ ├── loader.asm │ └── mbr.asm └── page-memory │ ├── bochsrc │ ├── build.sh │ ├── clean.sh │ ├── include │ └── boot.inc │ ├── loader.asm │ └── mbr.asm ├── chapter6 ├── bochsrc ├── build.sh ├── clean.sh ├── include │ └── boot.inc ├── kernel │ └── main.c ├── lib │ ├── kernel │ │ ├── print.asm │ │ └── print.h │ └── stdint.h ├── loader.asm └── mbr.asm ├── chapter7 ├── improve │ ├── bochsrc │ ├── build.sh │ ├── clean.sh │ ├── include │ │ └── boot.inc │ ├── kernel │ │ ├── global.h │ │ ├── init.c │ │ ├── init.h │ │ ├── interrupt.c │ │ ├── interrupt.h │ │ ├── io.h │ │ ├── kernel.asm │ │ └── main.c │ ├── lib │ │ ├── kernel │ │ │ ├── print.asm │ │ │ └── print.h │ │ └── stdint.h │ ├── loader.asm │ └── mbr.asm ├── timer │ ├── bochsrc │ ├── build.sh │ ├── clean.sh │ ├── device │ │ ├── timer.c │ │ └── timer.h │ ├── include │ │ └── boot.inc │ ├── kernel │ │ ├── global.h │ │ ├── init.c │ │ ├── init.h │ │ ├── interrupt.c │ │ ├── interrupt.h │ │ ├── io.h │ │ ├── kernel.asm │ │ └── main.c │ ├── lib │ │ ├── kernel │ │ │ ├── print.asm │ │ │ └── print.h │ │ └── stdint.h │ ├── loader.asm │ └── mbr.asm └── with_asm │ ├── bochsrc │ ├── build.sh │ ├── clean.sh │ ├── include │ └── boot.inc │ ├── kernel │ ├── global.h │ ├── init.c │ ├── init.h │ ├── interrupt.c │ ├── interrupt.h │ ├── io.h │ ├── kernel.asm │ └── main.c │ ├── lib │ ├── kernel │ │ ├── print.asm │ │ └── print.h │ └── stdint.h │ ├── loader.asm │ └── mbr.asm ├── chapter8 ├── assert │ ├── bochsrc │ ├── device │ │ ├── timer.c │ │ └── timer.h │ ├── include │ │ └── boot.inc │ ├── kernel │ │ ├── debug.c │ │ ├── debug.h │ │ ├── global.h │ │ ├── init.c │ │ ├── init.h │ │ ├── interrupt.c │ │ ├── interrupt.h │ │ ├── io.h │ │ ├── kernel.asm │ │ └── main.c │ ├── lib │ │ ├── kernel │ │ │ ├── print.asm │ │ │ └── print.h │ │ └── stdint.h │ ├── loader.asm │ ├── makefile │ └── mbr.asm └── memory_manager │ ├── bochsrc │ ├── device │ ├── timer.c │ └── timer.h │ ├── include │ └── boot.inc │ ├── kernel │ ├── debug.c │ ├── debug.h │ ├── global.h │ ├── init.c │ ├── init.h │ ├── interrupt.c │ ├── interrupt.h │ ├── io.h │ ├── kernel.asm │ ├── main.c │ ├── memory.c │ └── memory.h │ ├── lib │ ├── bitmap.c │ ├── bitmap.h │ ├── kernel │ │ ├── print.asm │ │ └── print.h │ ├── stdint.h │ ├── string.c │ └── string.h │ ├── loader.asm │ ├── makefile │ └── mbr.asm ├── chapter9 ├── thread_schedule │ ├── bochsrc.bxrc │ ├── device │ │ ├── timer.c │ │ └── timer.h │ ├── include │ │ └── boot.inc │ ├── kernel │ │ ├── debug.c │ │ ├── debug.h │ │ ├── global.h │ │ ├── init.c │ │ ├── init.h │ │ ├── interrupt.c │ │ ├── interrupt.h │ │ ├── io.h │ │ ├── kernel.asm │ │ ├── main.c │ │ ├── memory.c │ │ ├── memory.h │ │ ├── switch.asm │ │ ├── thread.c │ │ └── thread.h │ ├── lib │ │ ├── bitmap.c │ │ ├── bitmap.h │ │ ├── kernel │ │ │ ├── list.c │ │ │ ├── list.h │ │ │ ├── print.asm │ │ │ └── print.h │ │ ├── stdint.h │ │ ├── string.c │ │ └── string.h │ ├── loader.asm │ ├── makefile │ └── mbr.asm └── thread_start │ ├── bochsrc.bxrc │ ├── device │ ├── timer.c │ └── timer.h │ ├── include │ └── boot.inc │ ├── kernel │ ├── debug.c │ ├── debug.h │ ├── global.h │ ├── init.c │ ├── init.h │ ├── interrupt.c │ ├── interrupt.h │ ├── io.h │ ├── kernel.asm │ ├── main.c │ ├── memory.c │ ├── memory.h │ ├── thread.c │ └── thread.h │ ├── lib │ ├── bitmap.c │ ├── bitmap.h │ ├── kernel │ │ ├── print.asm │ │ └── print.h │ ├── stdint.h │ ├── string.c │ └── string.h │ ├── loader.asm │ ├── makefile │ └── mbr.asm └── images ├── chapter_10_with_lock.png ├── chapter_3_result.png ├── chapter_4_result.png ├── chapter_5_detect_memory.png ├── chapter_5_memory_size.png ├── chapter_5_page_memory.png ├── chapter_6_put_int.png ├── chapter_6_put_str.png ├── chapter_7_improve.png ├── chapter_7_timer.png ├── chapter_7_with_asm.png ├── chapter_8_assert.png ├── chapter_8_malloc.png ├── chapter_8_memory_pool.png ├── chapter_9_thread_schedule.png ├── chapter_9_thread_start.png └── thread_schedule_graph.png /.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | *.out 3 | *.lock 4 | *.img 5 | chapter11/.vscode/ 6 | -------------------------------------------------------------------------------- /chapter10/keyboard/bochsrc.bxrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 启动方式 7 | boot: disk 8 | 9 | # 关闭鼠标 10 | mouse: enabled=0 11 | 12 | # 硬盘设置 13 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 14 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 15 | -------------------------------------------------------------------------------- /chapter10/keyboard/device/console.c: -------------------------------------------------------------------------------- 1 | # include "console.h" 2 | # include "kernel/print.h" 3 | # include "stdint.h" 4 | # include "thread/sync.h" 5 | # include "thread/thread.h" 6 | 7 | static struct lock console_lock; 8 | 9 | void console_init() { 10 | lock_init(&console_lock); 11 | } 12 | 13 | void console_acquire() { 14 | lock_acquire(&console_lock); 15 | } 16 | 17 | void console_release() { 18 | lock_release(&console_lock); 19 | } 20 | 21 | void console_put_str(char* str) { 22 | console_acquire(); 23 | put_str(str); 24 | console_release(); 25 | } 26 | 27 | void console_put_char(uint8_t char_asci) { 28 | console_acquire(); 29 | put_char(char_asci); 30 | console_release(); 31 | } 32 | 33 | void console_put_int(uint32_t num) { 34 | console_acquire(); 35 | put_int(num); 36 | console_release(); 37 | } -------------------------------------------------------------------------------- /chapter10/keyboard/device/console.h: -------------------------------------------------------------------------------- 1 | # ifndef _DEVICE_CONSOLE_H 2 | # define _DEVICE_CONSOLE_H 3 | 4 | # include "stdint.h" 5 | 6 | void console_init(); 7 | void console_acquire(); 8 | void console_release(); 9 | void console_put_str(char* str); 10 | void console_put_char(uint8_t char_asci); 11 | void console_put_int(uint32_t num); 12 | 13 | # endif -------------------------------------------------------------------------------- /chapter10/keyboard/device/ioqueue.c: -------------------------------------------------------------------------------- 1 | # include "ioqueue.h" 2 | # include "interrupt.h" 3 | # include "global.h" 4 | # include "debug.h" 5 | 6 | void ioqueue_init(struct ioqueue* queue) { 7 | lock_init(&queue->lock); 8 | queue->head = queue->tail = 0; 9 | queue->producer = queue->tail = NULL; 10 | } 11 | 12 | static int32_t next_pos(int32_t pos) { 13 | return (pos + 1) % buf_size; 14 | } 15 | 16 | int is_queue_full(struct ioqueue* queue) { 17 | return next_pos(queue->head) == queue->tail; 18 | } 19 | 20 | int is_queue_empty(struct ioqueue* queue) { 21 | return queue->head == queue->tail; 22 | } 23 | 24 | static void queue_wait(struct task_struct** waiter) { 25 | *waiter = running_thread(); 26 | thread_block(TASK_BLOCKED); 27 | } 28 | 29 | static void wakeup(struct task_struct** waiter) { 30 | thread_unblock(*waiter); 31 | *waiter = NULL; 32 | } 33 | 34 | /** 35 | * 从给定的队列中获取一个字符,如果队列为空,那么等待. 36 | */ 37 | char queue_getchar(struct ioqueue* queue) { 38 | ASSERT(intr_get_status() == INTR_OFF); 39 | 40 | while (is_queue_empty(queue)) { 41 | lock_acquire(&queue->lock); 42 | // 这里同时会把ioqueue的consumer置为当前线程 43 | queue_wait(&queue->consumer); 44 | lock_release(&queue->lock); 45 | } 46 | 47 | char byte = queue->buf[queue->tail]; 48 | queue->tail = next_pos(queue->tail); 49 | 50 | if (queue->producer != NULL) { 51 | // 在无锁的情况下调用解除阻塞操作,因为bochs是单核CPU且屏蔽了中断,所以是安全的 52 | wakeup(&queue->producer); 53 | } 54 | 55 | return byte; 56 | } 57 | 58 | char queue_putchar(struct ioqueue* queue, char byte) { 59 | ASSERT(intr_get_status() == INTR_OFF); 60 | 61 | while (is_queue_full(queue)) { 62 | lock_acquire(&queue->lock); 63 | queue_wait(&queue->producer); 64 | lock_release(&queue->lock); 65 | } 66 | 67 | queue->buf[queue->head] = byte; 68 | queue->head = next_pos(queue->head); 69 | 70 | if (queue->consumer != NULL) { 71 | wakeup(&queue->consumer); 72 | } 73 | } -------------------------------------------------------------------------------- /chapter10/keyboard/device/ioqueue.h: -------------------------------------------------------------------------------- 1 | # ifndef _DEVICE_IOQUEUE_H 2 | # define _DEVICE_IOQUEUE_H 3 | 4 | # include "stdint.h" 5 | # include "thread/thread.h" 6 | # include "thread/sync.h" 7 | 8 | # define buf_size 64 9 | 10 | struct ioqueue { 11 | // 感觉这个锁然并卵 12 | struct lock* lock; 13 | struct task_struct* producer; 14 | struct task_struct* consumer; 15 | char buf[buf_size]; 16 | int32_t head; 17 | int32_t tail; 18 | }; 19 | 20 | int is_queue_full(struct ioqueue* queue); 21 | void ioqueue_init(struct ioqueue* queue); 22 | int is_queue_empty(struct ioqueue* queue); 23 | char queue_getchar(struct ioqueue* queue); 24 | char queue_putchar(struct ioqueue* queue, char byte); 25 | 26 | # endif -------------------------------------------------------------------------------- /chapter10/keyboard/device/keyboard.h: -------------------------------------------------------------------------------- 1 | # ifndef _DEVICE_KEYBOARD_H 2 | # define _DEVICE_KEYBOARD_H 3 | 4 | void keyboard_init(void); 5 | 6 | # endif -------------------------------------------------------------------------------- /chapter10/keyboard/device/timer.c: -------------------------------------------------------------------------------- 1 | # include "io.h" 2 | # include "kernel/print.h" 3 | # include "interrupt.h" 4 | # include "thread/thread.h" 5 | # include "debug.h" 6 | 7 | # define IRQ0_FREQUENCY 1000 8 | # define INPUT_FREQUENCY 1193180 9 | # define COUNTER0_VALUE INPUT_FREQUENCY / IRQ0_FREQUENCY 10 | # define COUNTER0_PORT 0x40 11 | # define COUNTER_MODE 2 12 | # define COUNTER0_NO 0 13 | # define READ_WRITE_LATCH 3 14 | # define PIT_CONTROL_PORT 0x43 15 | 16 | /** 17 | * 内核自开启中断后所有的嘀嗒数. 18 | */ 19 | uint32_t ticks; 20 | 21 | static void frequency_set(uint8_t counter_port, 22 | uint8_t counter_no, 23 | uint8_t rwl, 24 | uint8_t counter_mode, 25 | uint16_t counter_value) { 26 | outb(PIT_CONTROL_PORT, (uint8_t) (counter_no << 6 | rwl << 4 | counter_mode << 1)); 27 | outb(counter_port, (uint8_t) counter_value); 28 | outb(counter_port, (uint8_t) counter_value >> 8); 29 | } 30 | 31 | static void intr_timer_handler(void) { 32 | struct task_struct* cur_thread = running_thread(); 33 | 34 | ASSERT(cur_thread->stack_magic == 0x77777777); 35 | 36 | cur_thread->elaspsed_ticks++; 37 | ticks++; 38 | 39 | if (cur_thread->ticks == 0) { 40 | schedule(); 41 | } else { 42 | cur_thread->ticks--; 43 | } 44 | } 45 | 46 | /** 47 | * 初始化PIT 8253. 48 | */ 49 | void timer_init() { 50 | put_str("timer_init start.\n"); 51 | frequency_set(COUNTER0_PORT, COUNTER0_NO, READ_WRITE_LATCH, COUNTER_MODE, COUNTER0_VALUE); 52 | register_handler(0x20, intr_timer_handler); 53 | put_str("timer_init done.\n"); 54 | } -------------------------------------------------------------------------------- /chapter10/keyboard/device/timer.h: -------------------------------------------------------------------------------- 1 | void timer_init(); -------------------------------------------------------------------------------- /chapter10/keyboard/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_START_SECTOR equ 0x9 6 | KERNEL_BIN_BASE_ADDR equ 0x70000 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ; gdt描述符属性 10 | ; 段描述符高23位,表示段界限的粒度为4KB 11 | DESC_G_4K equ 100000000000000000000000b 12 | 13 | ; D/B为,1表示运行在32位模式下 14 | DESC_D_32 equ 10000000000000000000000b 15 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 16 | DESC_L equ 0000000000000000000000b 17 | ; 没有明确的用途,取值随意 18 | DESC_AVL equ 000000000000000000000b 19 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 20 | DESC_LIMIT_CODE2 equ 11110000000000000000b 21 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 22 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 23 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 24 | DESC_P equ 1000000000000000b 25 | DESC_DPL_0 equ 000000000000000b 26 | DESC_DPL_1 equ 010000000000000b 27 | DESC_DPL_2 equ 100000000000000b 28 | DESC_DPL_3 equ 110000000000000b 29 | DESC_S_CODE equ 1000000000000b 30 | DESC_S_DATA equ DESC_S_CODE 31 | DESC_S_sys equ 0000000000000b 32 | DESC_TYPE_CODE equ 100000000000b 33 | DESC_TYPE_DATA equ 001000000000b 34 | 35 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 36 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 39 | 40 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 45 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 46 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 47 | 48 | ; 选择字属性 49 | RPL0 equ 00b 50 | RPL1 equ 01b 51 | RPL2 equ 10b 52 | RPL3 equ 11b 53 | TI_GDT equ 000b 54 | TI_LDT equ 100b 55 | 56 | ; 页表相关属性 57 | PG_P equ 1b 58 | PG_RW_R equ 00b 59 | PG_RW_W equ 10b 60 | PG_US_S equ 000b 61 | PG_US_U equ 100b 62 | 63 | PT_NULL equ 0 -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/debug.c: -------------------------------------------------------------------------------- 1 | # include "debug.h" 2 | # include "kernel/print.h" 3 | # include "interrupt.h" 4 | 5 | void panic_spin(char* filename, int line, const char* func, const char* condition) { 6 | intr_disable(); 7 | 8 | put_str("Something wrong..."); 9 | 10 | put_str("FileName: "); 11 | put_str(filename); 12 | put_char('\n'); 13 | 14 | put_str("Line: "); 15 | put_int(line); 16 | put_char('\n'); 17 | 18 | put_str("Function: "); 19 | put_str(func); 20 | put_char('\n'); 21 | 22 | put_str("Condition: "); 23 | put_str(condition); 24 | put_char('\n'); 25 | 26 | while (1); 27 | } -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/debug.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_DEBUG_H 2 | # define _KERNEL_DEBUG_H 3 | 4 | void panic_spin(char* filename, int line, const char* func, const char* condition); 5 | 6 | /** 7 | * 当断言被触发时调用. 8 | * _FILE_: 内置宏,表示调用的文件名 9 | * _LINE_: 内置宏,被编译文件的行号 10 | * _func_: 内置宏: 被编译的函数名 11 | * _VA_ARGS_: 函数调用参数 12 | */ 13 | # define PANIC(...) panic_spin (__FILE__, __LINE__, __func__, __VA_ARGS__) 14 | 15 | # ifdef NDEBUG 16 | # define ASSERT(CONDITION) ((void) 0) 17 | # else 18 | # define ASSERT(CONDITION) \ 19 | if (CONDITION) { \ 20 | } else { \ 21 | PANIC(#CONDITION); \ 22 | } 23 | # endif 24 | # endif -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/global.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_GLOBAL_H 2 | #define _KERNEL_GLOBAL_H 3 | 4 | # include "stdint.h" 5 | 6 | # define RPL0 0 7 | # define RPL1 1 8 | # define RPL2 2 9 | # define RPL3 3 10 | 11 | # define TI_GDT 0 12 | # define TI_LDT 1 13 | 14 | # define SELECTOR_K_CODE ((1 << 3) + (TI_GDT << 2) + RPL0) 15 | # define SELECTOR_K_DATA ((2 << 3) + (TI_GDT << 2) + RPL0) 16 | # define SELECTOR_K_STACK SELECTOR_K_DATA 17 | # define SELECTOR_K_GS ((3 << 3) + (TI_GDT << 2) + RPL0) 18 | 19 | /* IDT描述符属性 */ 20 | # define IDT_DESC_P 1 21 | # define IDT_DESC_DPL0 0 22 | # define IDT_DESC_DPL3 3 23 | # define IDT_DESC_32_TYPE 0xE 24 | # define IDT_DESC_16_TYPE 0x6 25 | 26 | # define IDT_DESC_ATTR_DPL0 \ 27 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL0 << 5) + IDT_DESC_32_TYPE) 28 | 29 | # define IDT_DESC_ATTR_DPL3 \ 30 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL3 << 5) + IDT_DESC_32_TYPE) 31 | 32 | # define NULL 0 33 | 34 | #endif -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/init.c: -------------------------------------------------------------------------------- 1 | # include "init.h" 2 | # include "kernel/print.h" 3 | # include "timer.h" 4 | # include "memory.h" 5 | # include "thread/thread.h" 6 | # include "console.h" 7 | # include "keyboard.h" 8 | 9 | void init_all() { 10 | put_str("init_all.\n"); 11 | idt_init(); 12 | mem_init(); 13 | thread_init(); 14 | timer_init(); 15 | console_init(); 16 | keyboard_init(); 17 | } -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/init.h: -------------------------------------------------------------------------------- 1 | void init_all(void); -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/interrupt.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_INTERRUPT_H 2 | # define _KERNEL_INTERRUPT_H 3 | 4 | # include "stdint.h" 5 | 6 | typedef void* intr_handler; 7 | 8 | void idt_init(void); 9 | 10 | /** 11 | * 中断状态. 12 | */ 13 | enum intr_status { 14 | INTR_OFF, 15 | INTR_ON 16 | }; 17 | 18 | enum intr_status intr_get_status(void); 19 | enum intr_status intr_set_status(enum intr_status); 20 | enum intr_status intr_enable(void); 21 | enum intr_status intr_disable(void); 22 | void register_handler(uint8_t vec_no, intr_handler handler); 23 | 24 | # endif 25 | -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_IO_H 2 | # define _LIB_IO_H 3 | 4 | # include "stdint.h" 5 | 6 | /** 7 | * 向指定的端口写入一个字节的数据. 8 | */ 9 | static inline void outb(uint16_t port, uint8_t data) { 10 | asm volatile ("outb %b0, %w1" : : "a" (data), "Nd" (port)); 11 | } 12 | 13 | /** 14 | * 将addr起始处的word_cnt个字节写入端口port. 15 | */ 16 | static inline void outsw(uint16_t port, const void* addr, uint32_t word_cnt) { 17 | asm volatile ("cld; rep outsw" : "+S" (addr), "+c" (word_cnt) : "d" (port)); 18 | } 19 | 20 | /** 21 | * 将从端口port读入的一个字节返回. 22 | */ 23 | static inline uint8_t inb(uint16_t port) { 24 | uint8_t data; 25 | asm volatile ("inb %w1, %b0" : "=a" (data) : "Nd" (port)); 26 | return data; 27 | } 28 | 29 | /** 30 | * 将从port读取的word_cnt字节写入addr. 31 | */ 32 | static inline void insw(uint16_t port, void* addr, uint32_t word_cnt) { 33 | asm volatile ("cld; rep insw" : "+D" (addr), "+c" (word_cnt) : "d" (port) : "memory"); 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/kernel.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ; 对于CPU会自动压入错误码的中断类型,无需额外的操作 4 | %define ERROR_CODE nop 5 | ; 如果CPU没有压入错误码,为了保持处理逻辑的一致性,我们需要手动压入一个0 6 | %define ZERO push 0 7 | 8 | extern put_str 9 | ; 中断处理函数数组 10 | extern idt_table 11 | 12 | section .data 13 | intr_str db "interrupt occur!", 0xa, 0 14 | global intr_entry_table 15 | intr_entry_table: 16 | 17 | ; 中断处理程序宏定义 18 | %macro VECTOR 2 19 | section .text 20 | intr%1entry: 21 | 22 | %2 23 | ; 保存上下文 24 | push ds 25 | push es 26 | push fs 27 | push gs 28 | pushad 29 | 30 | mov al, 0x20 31 | out 0xa0, al 32 | out 0x20, al 33 | 34 | push %1 35 | 36 | ; 调用C的中断处理函数 37 | call [idt_table + 4 * %1] 38 | jmp intr_exit 39 | 40 | section .data 41 | dd intr%1entry 42 | 43 | %endmacro 44 | 45 | section .text 46 | global intr_exit 47 | intr_exit: 48 | add esp, 4 49 | popad 50 | pop gs 51 | pop fs 52 | pop es 53 | pop ds 54 | add esp, 4 55 | iretd 56 | 57 | VECTOR 0x00, ZERO 58 | VECTOR 0x01, ZERO 59 | VECTOR 0x02, ZERO 60 | VECTOR 0x03, ZERO 61 | VECTOR 0x04, ZERO 62 | VECTOR 0x05, ZERO 63 | VECTOR 0x06, ZERO 64 | VECTOR 0x07, ZERO 65 | VECTOR 0x08, ZERO 66 | VECTOR 0x09, ZERO 67 | VECTOR 0x0a, ZERO 68 | VECTOR 0x0b, ZERO 69 | VECTOR 0x0c, ZERO 70 | VECTOR 0x0d, ZERO 71 | VECTOR 0x0e, ZERO 72 | VECTOR 0x0f, ZERO 73 | VECTOR 0x10, ZERO 74 | VECTOR 0x11, ZERO 75 | VECTOR 0x12, ZERO 76 | VECTOR 0x13, ZERO 77 | VECTOR 0x14, ZERO 78 | VECTOR 0x15, ZERO 79 | VECTOR 0x16, ZERO 80 | VECTOR 0x17, ZERO 81 | VECTOR 0x18, ZERO 82 | VECTOR 0x19, ZERO 83 | VECTOR 0x1a, ZERO 84 | VECTOR 0x1b, ZERO 85 | VECTOR 0x1c, ZERO 86 | VECTOR 0x1d, ZERO 87 | VECTOR 0x1e, ERROR_CODE 88 | VECTOR 0x1f, ZERO 89 | VECTOR 0x20, ZERO 90 | VECTOR 0x21, ZERO 91 | VECTOR 0x22, ZERO 92 | VECTOR 0x23, ZERO 93 | VECTOR 0x24, ZERO 94 | VECTOR 0x25, ZERO 95 | VECTOR 0x26, ZERO 96 | VECTOR 0x27, ZERO 97 | VECTOR 0x28, ZERO 98 | VECTOR 0x29, ZERO 99 | VECTOR 0x2a, ZERO 100 | VECTOR 0x2b, ZERO 101 | VECTOR 0x2c, ZERO 102 | VECTOR 0x2d, ZERO 103 | VECTOR 0x2e, ZERO 104 | VECTOR 0x2f, ZERO -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/main.c: -------------------------------------------------------------------------------- 1 | # include "kernel/print.h" 2 | # include "init.h" 3 | # include "interrupt.h" 4 | 5 | int main(void) { 6 | // 这里不能使用console_put_str,因为还没有初始化 7 | put_str("I am kernel.\n"); 8 | init_all(); 9 | 10 | intr_enable(); 11 | 12 | while (1); 13 | 14 | return 0; 15 | } -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/memory.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_MEMORY_H 2 | # define _KERNEL_MEMORY_H 3 | 4 | # include "stdint.h" 5 | # include "bitmap.h" 6 | 7 | // 存在标志 8 | # define PG_P_1 1 9 | # define PG_P_0 0 10 | // 只读 11 | # define PG_RW_R 0 12 | // 可写 13 | # define PG_RW_W 2 14 | // 系统级 15 | # define PG_US_S 0 16 | # define PG_US_U 4 17 | 18 | /** 19 | * 内存池类型标志. 20 | */ 21 | enum pool_flags { 22 | // 内核类型 23 | PF_KERNEL = 1, 24 | PF_USER = 2 25 | }; 26 | 27 | struct virtual_addr { 28 | struct bitmap vaddr_bitmap; 29 | // 虚拟内存的起始地址 30 | uint32_t vaddr_start; 31 | }; 32 | 33 | extern struct pool kernel_pool, user_pool; 34 | 35 | void mem_init(void); 36 | 37 | void* get_kernel_pages(uint32_t page_count); 38 | 39 | void* malloc_page(enum pool_flags pf, uint32_t page_count); 40 | 41 | # endif -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/switch.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | section .text 3 | global switch_to 4 | switch_to: 5 | ; 将中断处理函数的上下文保存到目标PCB的栈中 6 | ; 这里隐含的是下次调度返回的地址其实是switch_to的返回地址 7 | push esi 8 | push edi 9 | push ebx 10 | push ebp 11 | mov eax, [esp + 20] 12 | mov [eax], esp 13 | 14 | ; 跳到目标PCB执行 15 | mov eax, [esp + 24] 16 | mov esp, [eax] 17 | pop ebp 18 | pop ebx 19 | pop edi 20 | pop esi 21 | ret -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/thread/sync.c: -------------------------------------------------------------------------------- 1 | # include "sync.h" 2 | # include "interrupt.h" 3 | # include "debug.h" 4 | 5 | void semaphore_init(struct semaphore* psem, uint8_t value) { 6 | psem->value = value; 7 | list_init(&psem->waiters); 8 | } 9 | 10 | void lock_init(struct lock* lock) { 11 | lock->holder = NULL; 12 | lock->holder_repeat_num = 0; 13 | semaphore_init(&lock->semaphore, 1); 14 | } 15 | 16 | void semaphore_down(struct semaphore* psem) { 17 | enum intr_status old_status = intr_disable(); 18 | 19 | while (psem->value == 0) { 20 | struct task_struct* cur = running_thread(); 21 | ASSERT(!list_find(&psem->waiters, &cur->general_tag)); 22 | list_append(&psem->waiters, &cur->general_tag); 23 | thread_block(TASK_BLOCKED); 24 | } 25 | 26 | psem->value--; 27 | ASSERT(psem->value == 0); 28 | intr_set_status(old_status); 29 | } 30 | 31 | void semaphore_up(struct semaphore* psem) { 32 | enum intr_status old_status = intr_disable(); 33 | ASSERT(psem->value == 0); 34 | 35 | if (!list_empty(&psem->waiters)) { 36 | struct task_struct* waiter = elem2entry(struct task_struct, general_tag, list_pop(&psem->waiters)); 37 | thread_unblock(waiter); 38 | } 39 | 40 | psem->value++; 41 | ASSERT(psem->value == 1); 42 | intr_set_status(old_status); 43 | } 44 | 45 | /** 46 | * 申请锁. 47 | */ 48 | void lock_acquire(struct lock* plock) { 49 | struct task_struct* cur = running_thread(); 50 | if (plock->holder != cur) { 51 | semaphore_down(&plock->semaphore); 52 | plock->holder = cur; 53 | ASSERT(plock->holder_repeat_num == 0); 54 | plock->holder_repeat_num = 1; 55 | } else { 56 | plock->holder_repeat_num++; 57 | } 58 | } 59 | 60 | /** 61 | * 锁释放. 62 | */ 63 | void lock_release(struct lock* plock) { 64 | ASSERT(plock->holder == running_thread()); 65 | 66 | if (plock->holder_repeat_num > 1) { 67 | plock->holder_repeat_num--; 68 | return; 69 | } 70 | 71 | ASSERT(plock->holder_repeat_num == 1); 72 | 73 | plock->holder = NULL; 74 | plock->holder_repeat_num = 0; 75 | semaphore_up(&plock->semaphore); 76 | } -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/thread/sync.h: -------------------------------------------------------------------------------- 1 | # ifndef _THREAD_SYNC_H 2 | # define _THREAD_SYNC_H 3 | 4 | # include "kernel/list.h" 5 | # include "thread.h" 6 | # include "stdint.h" 7 | 8 | /** 9 | * 信号量. 10 | */ 11 | struct semaphore { 12 | uint8_t value; 13 | struct list waiters; 14 | }; 15 | 16 | struct lock { 17 | struct task_struct* holder; 18 | struct semaphore semaphore; 19 | uint32_t holder_repeat_num; 20 | }; 21 | 22 | void semaphore_init(struct semaphore* psem, uint8_t value); 23 | void lock_init(struct lock* lock); 24 | void semaphore_down(struct semaphore* psem); 25 | void semaphore_up(struct semaphore* psem); 26 | void lock_acquire(struct lock* plock); 27 | void lock_release(struct lock* plock); 28 | 29 | # endif -------------------------------------------------------------------------------- /chapter10/keyboard/kernel/thread/thread.h: -------------------------------------------------------------------------------- 1 | # ifndef _THREAD_H 2 | # define _THREAD_H 3 | 4 | # include "stdint.h" 5 | # include "kernel/list.h" 6 | 7 | /** 8 | * 自定义通用函数类型. 9 | */ 10 | typedef void thread_func(void*); 11 | 12 | /** 13 | * 线程状态. 14 | */ 15 | enum task_status { 16 | TASK_RUNNING, 17 | TASK_READY, 18 | TASK_BLOCKED, 19 | TASK_WAITTING, 20 | TASK_HANGING, 21 | TASK_DIED 22 | }; 23 | 24 | /** 25 | * 中断栈. 26 | */ 27 | struct intr_stack { 28 | uint32_t vec_no; 29 | uint32_t edi; 30 | uint32_t esi; 31 | uint32_t ebp; 32 | uint32_t esp_dummy; 33 | uint32_t ebx; 34 | uint32_t edx; 35 | uint32_t ecx; 36 | uint32_t eax; 37 | uint32_t gs; 38 | uint32_t fs; 39 | uint32_t es; 40 | uint32_t ds; 41 | 42 | // 下面的属性由CPU从低特权级进入高特权级时压入 43 | uint32_t err_code; 44 | void (*eip) (void); 45 | uint32_t cs; 46 | uint32_t eflags; 47 | void* esp; 48 | uint32_t ss; 49 | }; 50 | 51 | struct thread_stack { 52 | uint32_t ebp; 53 | uint32_t ebx; 54 | uint32_t edi; 55 | uint32_t esi; 56 | 57 | // 第一次执行时指向待调用的函数kernel_thread,其它时候指向switch_to的返回地址. 58 | void (*eip) (thread_func* func, void* func_args); 59 | 60 | void (*unused_retaddr); 61 | thread_func* function; 62 | void* func_args; 63 | }; 64 | 65 | /** 66 | * PCB,进程或线程的控制块. 67 | */ 68 | struct task_struct { 69 | // 内核栈 70 | uint32_t* self_kstack; 71 | enum task_status status; 72 | char name[16]; 73 | uint8_t priority; 74 | // 当前线程可以占用的CPU嘀嗒数 75 | uint8_t ticks; 76 | // 此任务占用的总嘀嗒数 77 | uint32_t elaspsed_ticks; 78 | // 可执行队列节点 79 | struct list_elem general_tag; 80 | // 所有不可运行线程队列节点 81 | struct list_elem all_list_tag; 82 | uint32_t* pgdir; 83 | uint32_t stack_magic; 84 | }; 85 | 86 | struct task_struct* running_thread(); 87 | void thread_create(struct task_struct* pthread, thread_func function, void* func_args); 88 | void init_thread(struct task_struct* pthread, char* name, int prio); 89 | struct task_struct* thread_start(char* name, int prio, thread_func function, void* func_args); 90 | void schedule(); 91 | void thread_init(); 92 | void thread_block(enum task_status status); 93 | void thread_unblock(struct task_struct* pthread); 94 | 95 | # endif -------------------------------------------------------------------------------- /chapter10/keyboard/lib/bitmap.c: -------------------------------------------------------------------------------- 1 | # include "bitmap.h" 2 | # include "stdint.h" 3 | # include "string.h" 4 | # include "kernel/print.h" 5 | # include "interrupt.h" 6 | # include "debug.h" 7 | 8 | void bitmap_init(struct bitmap* btmap) { 9 | memset(btmap->bits, 0, btmap->btmp_bytes_len); 10 | } 11 | 12 | /** 13 | * 检测指定位是否为1,如果是,返回1. 14 | */ 15 | int bitmap_scan_test(struct bitmap* btmap, uint32_t index) { 16 | uint32_t byte_index = (index / 8); 17 | uint32_t bit_odd = byte_index % 8; 18 | 19 | return (btmap->bits[byte_index] & BITMAP_MASK << bit_odd); 20 | } 21 | 22 | /** 23 | * 在位图中申请连续的cnt个位. 24 | */ 25 | int bitmap_scan(struct bitmap* btmap, uint32_t cnt) { 26 | uint32_t idx_byte = 0; 27 | 28 | // 以字节为单位进行查找 29 | while ((0xff == btmap->bits[idx_byte]) && idx_byte < btmap->btmp_bytes_len) { 30 | ++idx_byte; 31 | } 32 | 33 | // 没有找到 34 | if (idx_byte == btmap->btmp_bytes_len) { 35 | return -1; 36 | } 37 | 38 | // 找到了一个字节不全为1,那么在字节内部再次进行查找具体的起使位 39 | int idx_bit = 0; 40 | while ((uint8_t) BITMAP_MASK << idx_bit & btmap->bits[idx_byte]) { 41 | ++idx_bit; 42 | } 43 | 44 | // 起始位 45 | int bit_idx_start = (idx_byte * 8 + idx_bit); 46 | if (cnt == 1) { 47 | return bit_idx_start; 48 | } 49 | 50 | uint32_t bit_left = (btmap->btmp_bytes_len * 8 - bit_idx_start); 51 | uint32_t count = 1; 52 | 53 | uint32_t next_bit = bit_idx_start + 1; 54 | 55 | bit_idx_start = -1; 56 | while (bit_left-- > 0) { 57 | if (!(bitmap_scan_test(btmap, next_bit))) { 58 | ++count; 59 | } else { 60 | count = 0; 61 | } 62 | 63 | if (count == cnt) { 64 | bit_idx_start = (next_bit - cnt + 1); 65 | break; 66 | } 67 | 68 | next_bit++; 69 | } 70 | 71 | return bit_idx_start; 72 | } 73 | 74 | void bitmap_set(struct bitmap* btmap, uint32_t index, int8_t value) { 75 | ASSERT(value == 0 || value == 1); 76 | 77 | uint32_t byte_index = index / 8; 78 | uint32_t bit_odd = index % 8; 79 | 80 | if (value) { 81 | btmap->bits[byte_index] |= (BITMAP_MASK << bit_odd); 82 | } else { 83 | btmap->bits[byte_index] &= ~(BITMAP_MASK << bit_odd); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /chapter10/keyboard/lib/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_KERNEL_BITMAP_H 2 | #define _LIB_KERNEL_BITMAP_H 3 | 4 | # include "global.h" 5 | 6 | # define BITMAP_MASK 1 7 | 8 | struct bitmap { 9 | uint32_t btmp_bytes_len; 10 | uint8_t* bits; 11 | }; 12 | 13 | void bitmap_init(struct bitmap* btmap); 14 | 15 | int bitmap_scan_test(struct bitmap* btmap, uint32_t bit_idx); 16 | 17 | int bitmap_scan(struct bitmap* btmap, uint32_t cnt); 18 | 19 | void bitmap_set(struct bitmap* btmap, uint32_t index, int8_t value); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /chapter10/keyboard/lib/kernel/list.h: -------------------------------------------------------------------------------- 1 | # ifndef _LIB_KERNEL_LIST_H 2 | # define _LIB_KERNEL_LIST_H 3 | 4 | # include "global.h" 5 | 6 | /** 7 | * 获取结构体内成员在结构体的偏移. 8 | */ 9 | # define offset(struct_type, member) (int) (&((struct_type*)0)->member) 10 | 11 | # define elem2entry(struct_type, struct_member_name, elem_ptr) \ 12 | (struct_type*) ((int) elem_ptr - offset(struct_type, struct_member_name)) 13 | 14 | /** 15 | * 链表节点. 16 | */ 17 | struct list_elem { 18 | struct list_elem* prev; 19 | struct list_elem* next; 20 | }; 21 | 22 | /** 23 | * 链表结构. 24 | */ 25 | struct list { 26 | struct list_elem head; 27 | struct list_elem tail; 28 | }; 29 | 30 | /** 31 | * 用于链表遍历的回调函数. 32 | */ 33 | typedef int (function) (struct list_elem*, int arg); 34 | 35 | void list_init(struct list* list); 36 | void list_insert_before(struct list_elem* before, struct list_elem* elem); 37 | void list_push(struct list* list, struct list_elem* elem); 38 | void list_append(struct list* list, struct list_elem* elem); 39 | void list_remove(struct list_elem* elem); 40 | struct list_elem* list_pop(struct list* list); 41 | int list_find(struct list* list, struct list_elem* elem); 42 | int list_empty(struct list* list); 43 | uint32_t list_length(struct list* list); 44 | struct list_elem* list_traversal(struct list* list, function func, int arg); 45 | 46 | # endif -------------------------------------------------------------------------------- /chapter10/keyboard/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 为print.asm提供方便引用的头文件定义. 3 | */ 4 | # ifndef _LIB_KERNEL_PRINT_H 5 | # define _LIB_KERNEL_PRINT_H 6 | 7 | # include "stdint.h" 8 | 9 | void put_char(uint8_t char_asci); 10 | 11 | /** 12 | * 字符串打印,必须以\0结尾. 13 | */ 14 | void put_str(char* message); 15 | 16 | /** 17 | * 以16进制的形式打印数字. 18 | */ 19 | void put_int(uint32_t num); 20 | 21 | void set_cursor(uint32_t pos); 22 | 23 | # endif -------------------------------------------------------------------------------- /chapter10/keyboard/lib/stdint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 仿照/usr/include/stdint.h定义我们自己的数据类型. 3 | */ 4 | #ifndef _LIB_STDINT_H 5 | #define _LIB_STDINT_H 6 | 7 | typedef signed char int8_t; 8 | typedef signed short int int16_t; 9 | typedef signed int int32_t; 10 | typedef signed long long int int64_t; 11 | 12 | typedef unsigned char uint8_t; 13 | typedef unsigned short int uint16_t; 14 | typedef unsigned int uint32_t; 15 | typedef unsigned long long int uint64_t; 16 | 17 | #endif -------------------------------------------------------------------------------- /chapter10/keyboard/lib/string.h: -------------------------------------------------------------------------------- 1 | # ifndef _LIB_STRING_H 2 | # define _LIB_STRING_H 3 | 4 | # include "global.h" 5 | # include "debug.h" 6 | 7 | void memset(void* address, uint8_t value, uint32_t size); 8 | void memcpy(void* dst, const void* src, uint32_t size); 9 | int memcmp(const void* left, const void* right, uint32_t size); 10 | char* strcpy(char* dst, const char* src); 11 | uint32_t strlen(const char* str); 12 | int8_t strcmp(const char* left, const char* right); 13 | char* strchr(const char* str, const uint8_t c); 14 | char* strrchr(const char* str, const uint8_t c); 15 | char* strcat(char* dst, const char* src); 16 | uint32_t strchrs(const char* str, const uint8_t c); 17 | 18 | # endif -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/bochsrc.bxrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 启动方式 7 | boot: disk 8 | 9 | # 关闭鼠标 10 | mouse: enabled=0 11 | 12 | # 硬盘设置 13 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 14 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 15 | -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/device/console.c: -------------------------------------------------------------------------------- 1 | # include "console.h" 2 | # include "kernel/print.h" 3 | # include "stdint.h" 4 | # include "thread/sync.h" 5 | # include "thread/thread.h" 6 | 7 | static struct lock console_lock; 8 | 9 | void console_init() { 10 | lock_init(&console_lock); 11 | } 12 | 13 | void console_acquire() { 14 | lock_acquire(&console_lock); 15 | } 16 | 17 | void console_release() { 18 | lock_release(&console_lock); 19 | } 20 | 21 | void console_put_str(char* str) { 22 | console_acquire(); 23 | put_str(str); 24 | console_release(); 25 | } 26 | 27 | void console_put_char(uint8_t char_asci) { 28 | console_acquire(); 29 | put_char(char_asci); 30 | console_release(); 31 | } 32 | 33 | void console_put_int(uint32_t num) { 34 | console_acquire(); 35 | put_int(num); 36 | console_release(); 37 | } -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/device/console.h: -------------------------------------------------------------------------------- 1 | # ifndef _DEVICE_CONSOLE_H 2 | # define _DEVICE_CONSOLE_H 3 | 4 | # include "stdint.h" 5 | 6 | void console_init(); 7 | void console_acquire(); 8 | void console_release(); 9 | void console_put_str(char* str); 10 | void console_put_char(uint8_t char_asci); 11 | void console_put_int(uint32_t num); 12 | 13 | # endif -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/device/timer.c: -------------------------------------------------------------------------------- 1 | # include "io.h" 2 | # include "kernel/print.h" 3 | # include "interrupt.h" 4 | # include "thread/thread.h" 5 | # include "debug.h" 6 | 7 | # define IRQ0_FREQUENCY 1000 8 | # define INPUT_FREQUENCY 1193180 9 | # define COUNTER0_VALUE INPUT_FREQUENCY / IRQ0_FREQUENCY 10 | # define COUNTER0_PORT 0x40 11 | # define COUNTER_MODE 2 12 | # define COUNTER0_NO 0 13 | # define READ_WRITE_LATCH 3 14 | # define PIT_CONTROL_PORT 0x43 15 | 16 | /** 17 | * 内核自开启中断后所有的嘀嗒数. 18 | */ 19 | uint32_t ticks; 20 | 21 | static void frequency_set(uint8_t counter_port, 22 | uint8_t counter_no, 23 | uint8_t rwl, 24 | uint8_t counter_mode, 25 | uint16_t counter_value) { 26 | outb(PIT_CONTROL_PORT, (uint8_t) (counter_no << 6 | rwl << 4 | counter_mode << 1)); 27 | outb(counter_port, (uint8_t) counter_value); 28 | outb(counter_port, (uint8_t) counter_value >> 8); 29 | } 30 | 31 | static void intr_timer_handler(void) { 32 | struct task_struct* cur_thread = running_thread(); 33 | 34 | ASSERT(cur_thread->stack_magic == 0x77777777); 35 | 36 | cur_thread->elaspsed_ticks++; 37 | ticks++; 38 | 39 | if (cur_thread->ticks == 0) { 40 | schedule(); 41 | } else { 42 | cur_thread->ticks--; 43 | } 44 | } 45 | 46 | /** 47 | * 初始化PIT 8253. 48 | */ 49 | void timer_init() { 50 | put_str("timer_init start.\n"); 51 | frequency_set(COUNTER0_PORT, COUNTER0_NO, READ_WRITE_LATCH, COUNTER_MODE, COUNTER0_VALUE); 52 | register_handler(0x20, intr_timer_handler); 53 | put_str("timer_init done.\n"); 54 | } -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/device/timer.h: -------------------------------------------------------------------------------- 1 | void timer_init(); -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_START_SECTOR equ 0x9 6 | KERNEL_BIN_BASE_ADDR equ 0x70000 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ; gdt描述符属性 10 | ; 段描述符高23位,表示段界限的粒度为4KB 11 | DESC_G_4K equ 100000000000000000000000b 12 | 13 | ; D/B为,1表示运行在32位模式下 14 | DESC_D_32 equ 10000000000000000000000b 15 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 16 | DESC_L equ 0000000000000000000000b 17 | ; 没有明确的用途,取值随意 18 | DESC_AVL equ 000000000000000000000b 19 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 20 | DESC_LIMIT_CODE2 equ 11110000000000000000b 21 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 22 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 23 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 24 | DESC_P equ 1000000000000000b 25 | DESC_DPL_0 equ 000000000000000b 26 | DESC_DPL_1 equ 010000000000000b 27 | DESC_DPL_2 equ 100000000000000b 28 | DESC_DPL_3 equ 110000000000000b 29 | DESC_S_CODE equ 1000000000000b 30 | DESC_S_DATA equ DESC_S_CODE 31 | DESC_S_sys equ 0000000000000b 32 | DESC_TYPE_CODE equ 100000000000b 33 | DESC_TYPE_DATA equ 001000000000b 34 | 35 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 36 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 39 | 40 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 45 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 46 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 47 | 48 | ; 选择字属性 49 | RPL0 equ 00b 50 | RPL1 equ 01b 51 | RPL2 equ 10b 52 | RPL3 equ 11b 53 | TI_GDT equ 000b 54 | TI_LDT equ 100b 55 | 56 | ; 页表相关属性 57 | PG_P equ 1b 58 | PG_RW_R equ 00b 59 | PG_RW_W equ 10b 60 | PG_US_S equ 000b 61 | PG_US_U equ 100b 62 | 63 | PT_NULL equ 0 -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/debug.c: -------------------------------------------------------------------------------- 1 | # include "debug.h" 2 | # include "kernel/print.h" 3 | # include "interrupt.h" 4 | 5 | void panic_spin(char* filename, int line, const char* func, const char* condition) { 6 | intr_disable(); 7 | 8 | put_str("Something wrong..."); 9 | 10 | put_str("FileName: "); 11 | put_str(filename); 12 | put_char('\n'); 13 | 14 | put_str("Line: "); 15 | put_int(line); 16 | put_char('\n'); 17 | 18 | put_str("Function: "); 19 | put_str(func); 20 | put_char('\n'); 21 | 22 | put_str("Condition: "); 23 | put_str(condition); 24 | put_char('\n'); 25 | 26 | while (1); 27 | } -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/debug.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_DEBUG_H 2 | # define _KERNEL_DEBUG_H 3 | 4 | void panic_spin(char* filename, int line, const char* func, const char* condition); 5 | 6 | /** 7 | * 当断言被触发时调用. 8 | * _FILE_: 内置宏,表示调用的文件名 9 | * _LINE_: 内置宏,被编译文件的行号 10 | * _func_: 内置宏: 被编译的函数名 11 | * _VA_ARGS_: 函数调用参数 12 | */ 13 | # define PANIC(...) panic_spin (__FILE__, __LINE__, __func__, __VA_ARGS__) 14 | 15 | # ifdef NDEBUG 16 | # define ASSERT(CONDITION) ((void) 0) 17 | # else 18 | # define ASSERT(CONDITION) \ 19 | if (CONDITION) { \ 20 | } else { \ 21 | PANIC(#CONDITION); \ 22 | } 23 | # endif 24 | # endif -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/global.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_GLOBAL_H 2 | #define _KERNEL_GLOBAL_H 3 | 4 | # include "stdint.h" 5 | 6 | # define RPL0 0 7 | # define RPL1 1 8 | # define RPL2 2 9 | # define RPL3 3 10 | 11 | # define TI_GDT 0 12 | # define TI_LDT 1 13 | 14 | # define SELECTOR_K_CODE ((1 << 3) + (TI_GDT << 2) + RPL0) 15 | # define SELECTOR_K_DATA ((2 << 3) + (TI_GDT << 2) + RPL0) 16 | # define SELECTOR_K_STACK SELECTOR_K_DATA 17 | # define SELECTOR_K_GS ((3 << 3) + (TI_GDT << 2) + RPL0) 18 | 19 | /* IDT描述符属性 */ 20 | # define IDT_DESC_P 1 21 | # define IDT_DESC_DPL0 0 22 | # define IDT_DESC_DPL3 3 23 | # define IDT_DESC_32_TYPE 0xE 24 | # define IDT_DESC_16_TYPE 0x6 25 | 26 | # define IDT_DESC_ATTR_DPL0 \ 27 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL0 << 5) + IDT_DESC_32_TYPE) 28 | 29 | # define IDT_DESC_ATTR_DPL3 \ 30 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL3 << 5) + IDT_DESC_32_TYPE) 31 | 32 | # define NULL 0 33 | 34 | #endif -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/init.c: -------------------------------------------------------------------------------- 1 | # include "init.h" 2 | # include "kernel/print.h" 3 | # include "timer.h" 4 | # include "memory.h" 5 | # include "thread/thread.h" 6 | # include "console.h" 7 | 8 | void init_all() { 9 | put_str("init_all.\n"); 10 | idt_init(); 11 | mem_init(); 12 | thread_init(); 13 | timer_init(); 14 | console_init(); 15 | } -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/init.h: -------------------------------------------------------------------------------- 1 | void init_all(void); -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/interrupt.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_INTERRUPT_H 2 | # define _KERNEL_INTERRUPT_H 3 | 4 | # include "stdint.h" 5 | 6 | typedef void* intr_handler; 7 | 8 | void idt_init(void); 9 | 10 | /** 11 | * 中断状态. 12 | */ 13 | enum intr_status { 14 | INTR_OFF, 15 | INTR_ON 16 | }; 17 | 18 | enum intr_status intr_get_status(void); 19 | enum intr_status intr_set_status(enum intr_status); 20 | enum intr_status intr_enable(void); 21 | enum intr_status intr_disable(void); 22 | void register_handler(uint8_t vec_no, intr_handler handler); 23 | 24 | # endif 25 | -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_IO_H 2 | # define _LIB_IO_H 3 | 4 | # include "stdint.h" 5 | 6 | /** 7 | * 向指定的端口写入一个字节的数据. 8 | */ 9 | static inline void outb(uint16_t port, uint8_t data) { 10 | asm volatile ("outb %b0, %w1" : : "a" (data), "Nd" (port)); 11 | } 12 | 13 | /** 14 | * 将addr起始处的word_cnt个字节写入端口port. 15 | */ 16 | static inline void outsw(uint16_t port, const void* addr, uint32_t word_cnt) { 17 | asm volatile ("cld; rep outsw" : "+S" (addr), "+c" (word_cnt) : "d" (port)); 18 | } 19 | 20 | /** 21 | * 将从端口port读入的一个字节返回. 22 | */ 23 | static inline uint8_t inb(uint16_t port) { 24 | uint8_t data; 25 | asm volatile ("inb %w1, %b0" : "=a" (data) : "Nd" (port)); 26 | return data; 27 | } 28 | 29 | /** 30 | * 将从port读取的word_cnt字节写入addr. 31 | */ 32 | static inline void insw(uint16_t port, void* addr, uint32_t word_cnt) { 33 | asm volatile ("cld; rep insw" : "+D" (addr), "+c" (word_cnt) : "d" (port) : "memory"); 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/kernel.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ; 对于CPU会自动压入错误码的中断类型,无需额外的操作 4 | %define ERROR_CODE nop 5 | ; 如果CPU没有压入错误码,为了保持处理逻辑的一致性,我们需要手动压入一个0 6 | %define ZERO push 0 7 | 8 | extern put_str 9 | ; 中断处理函数数组 10 | extern idt_table 11 | 12 | section .data 13 | intr_str db "interrupt occur!", 0xa, 0 14 | global intr_entry_table 15 | intr_entry_table: 16 | 17 | ; 中断处理程序宏定义 18 | %macro VECTOR 2 19 | section .text 20 | intr%1entry: 21 | 22 | %2 23 | ; 保存上下文 24 | push ds 25 | push es 26 | push fs 27 | push gs 28 | pushad 29 | 30 | mov al, 0x20 31 | out 0xa0, al 32 | out 0x20, al 33 | 34 | push %1 35 | 36 | ; 调用C的中断处理函数 37 | call [idt_table + 4 * %1] 38 | jmp intr_exit 39 | 40 | section .data 41 | dd intr%1entry 42 | 43 | %endmacro 44 | 45 | section .text 46 | global intr_exit 47 | intr_exit: 48 | add esp, 4 49 | popad 50 | pop gs 51 | pop fs 52 | pop es 53 | pop ds 54 | add esp, 4 55 | iretd 56 | 57 | VECTOR 0x00, ZERO 58 | VECTOR 0x01, ZERO 59 | VECTOR 0x02, ZERO 60 | VECTOR 0x03, ZERO 61 | VECTOR 0x04, ZERO 62 | VECTOR 0x05, ZERO 63 | VECTOR 0x06, ZERO 64 | VECTOR 0x07, ZERO 65 | VECTOR 0x08, ZERO 66 | VECTOR 0x09, ZERO 67 | VECTOR 0x0a, ZERO 68 | VECTOR 0x0b, ZERO 69 | VECTOR 0x0c, ZERO 70 | VECTOR 0x0d, ZERO 71 | VECTOR 0x0e, ZERO 72 | VECTOR 0x0f, ZERO 73 | VECTOR 0x10, ZERO 74 | VECTOR 0x11, ZERO 75 | VECTOR 0x12, ZERO 76 | VECTOR 0x13, ZERO 77 | VECTOR 0x14, ZERO 78 | VECTOR 0x15, ZERO 79 | VECTOR 0x16, ZERO 80 | VECTOR 0x17, ZERO 81 | VECTOR 0x18, ZERO 82 | VECTOR 0x19, ZERO 83 | VECTOR 0x1a, ZERO 84 | VECTOR 0x1b, ZERO 85 | VECTOR 0x1c, ZERO 86 | VECTOR 0x1d, ZERO 87 | VECTOR 0x1e, ERROR_CODE 88 | VECTOR 0x1f, ZERO 89 | VECTOR 0x20, ZERO -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/main.c: -------------------------------------------------------------------------------- 1 | # include "kernel/print.h" 2 | # include "init.h" 3 | # include "thread/thread.h" 4 | # include "interrupt.h" 5 | # include "console.h" 6 | 7 | void k_thread_function_a(void*); 8 | void k_thread_function_b(void*); 9 | 10 | int main(void) { 11 | // 这里不能使用console_put_str,因为还没有初始化 12 | put_str("I am kernel.\n"); 13 | init_all(); 14 | 15 | thread_start("k_thread_a", 31, k_thread_function_a, "threadA "); 16 | thread_start("k_thread_b", 8, k_thread_function_b, "threadB "); 17 | 18 | intr_enable(); 19 | 20 | while (1) { 21 | console_put_str("main "); 22 | } 23 | 24 | return 0; 25 | } 26 | 27 | void k_thread_function_a(void* args) { 28 | // 这里必须是死循环,否则执行流并不会返回到main函数,所以CPU将会放飞自我,出发6号未知操作码异常 29 | while (1) { 30 | console_put_str((char*) args); 31 | } 32 | } 33 | 34 | void k_thread_function_b(void* args) { 35 | while (1) { 36 | console_put_str((char*) args); 37 | } 38 | } -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/memory.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_MEMORY_H 2 | # define _KERNEL_MEMORY_H 3 | 4 | # include "stdint.h" 5 | # include "bitmap.h" 6 | 7 | // 存在标志 8 | # define PG_P_1 1 9 | # define PG_P_0 0 10 | // 只读 11 | # define PG_RW_R 0 12 | // 可写 13 | # define PG_RW_W 2 14 | // 系统级 15 | # define PG_US_S 0 16 | # define PG_US_U 4 17 | 18 | /** 19 | * 内存池类型标志. 20 | */ 21 | enum pool_flags { 22 | // 内核类型 23 | PF_KERNEL = 1, 24 | PF_USER = 2 25 | }; 26 | 27 | struct virtual_addr { 28 | struct bitmap vaddr_bitmap; 29 | // 虚拟内存的起始地址 30 | uint32_t vaddr_start; 31 | }; 32 | 33 | extern struct pool kernel_pool, user_pool; 34 | 35 | void mem_init(void); 36 | 37 | void* get_kernel_pages(uint32_t page_count); 38 | 39 | void* malloc_page(enum pool_flags pf, uint32_t page_count); 40 | 41 | # endif -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/switch.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | section .text 3 | global switch_to 4 | switch_to: 5 | ; 将中断处理函数的上下文保存到目标PCB的栈中 6 | ; 这里隐含的是下次调度返回的地址其实是switch_to的返回地址 7 | push esi 8 | push edi 9 | push ebx 10 | push ebp 11 | mov eax, [esp + 20] 12 | mov [eax], esp 13 | 14 | ; 跳到目标PCB执行 15 | mov eax, [esp + 24] 16 | mov esp, [eax] 17 | pop ebp 18 | pop ebx 19 | pop edi 20 | pop esi 21 | ret -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/thread/sync.c: -------------------------------------------------------------------------------- 1 | # include "sync.h" 2 | # include "interrupt.h" 3 | # include "debug.h" 4 | 5 | void semaphore_init(struct semaphore* psem, uint8_t value) { 6 | psem->value = value; 7 | list_init(&psem->waiters); 8 | } 9 | 10 | void lock_init(struct lock* lock) { 11 | lock->holder = NULL; 12 | lock->holder_repeat_num = 0; 13 | semaphore_init(&lock->semaphore, 1); 14 | } 15 | 16 | void semaphore_down(struct semaphore* psem) { 17 | enum intr_status old_status = intr_disable(); 18 | 19 | while (psem->value == 0) { 20 | struct task_struct* cur = running_thread(); 21 | ASSERT(!list_find(&psem->waiters, &cur->general_tag)); 22 | list_append(&psem->waiters, &cur->general_tag); 23 | thread_block(TASK_BLOCKED); 24 | } 25 | 26 | psem->value--; 27 | ASSERT(psem->value == 0); 28 | intr_set_status(old_status); 29 | } 30 | 31 | void semaphore_up(struct semaphore* psem) { 32 | enum intr_status old_status = intr_disable(); 33 | ASSERT(psem->value == 0); 34 | 35 | if (!list_empty(&psem->waiters)) { 36 | struct task_struct* waiter = elem2entry(struct task_struct, general_tag, list_pop(&psem->waiters)); 37 | thread_unblock(waiter); 38 | } 39 | 40 | psem->value++; 41 | ASSERT(psem->value == 1); 42 | intr_set_status(old_status); 43 | } 44 | 45 | /** 46 | * 申请锁. 47 | */ 48 | void lock_acquire(struct lock* plock) { 49 | struct task_struct* cur = running_thread(); 50 | if (plock->holder != cur) { 51 | semaphore_down(&plock->semaphore); 52 | plock->holder = cur; 53 | ASSERT(plock->holder_repeat_num == 0); 54 | plock->holder_repeat_num = 1; 55 | } else { 56 | plock->holder_repeat_num++; 57 | } 58 | } 59 | 60 | /** 61 | * 锁释放. 62 | */ 63 | void lock_release(struct lock* plock) { 64 | ASSERT(plock->holder == running_thread()); 65 | 66 | if (plock->holder_repeat_num > 1) { 67 | plock->holder_repeat_num--; 68 | return; 69 | } 70 | 71 | ASSERT(plock->holder_repeat_num == 1); 72 | 73 | plock->holder = NULL; 74 | plock->holder_repeat_num = 0; 75 | semaphore_up(&plock->semaphore); 76 | } -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/kernel/thread/sync.h: -------------------------------------------------------------------------------- 1 | # ifndef _THREAD_SYNC_H 2 | # define _THREAD_SYNC_H 3 | 4 | # include "kernel/list.h" 5 | # include "thread.h" 6 | # include "stdint.h" 7 | 8 | /** 9 | * 信号量. 10 | */ 11 | struct semaphore { 12 | uint8_t value; 13 | struct list waiters; 14 | }; 15 | 16 | struct lock { 17 | struct task_struct* holder; 18 | struct semaphore semaphore; 19 | uint32_t holder_repeat_num; 20 | }; 21 | 22 | void semaphore_init(struct semaphore* psem, uint8_t value); 23 | void lock_init(struct lock* lock); 24 | void semaphore_down(struct semaphore* psem); 25 | void semaphore_up(struct semaphore* psem); 26 | void lock_acquire(struct lock* plock); 27 | void lock_release(struct lock* plock); 28 | 29 | # endif -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/lib/bitmap.c: -------------------------------------------------------------------------------- 1 | # include "bitmap.h" 2 | # include "stdint.h" 3 | # include "string.h" 4 | # include "kernel/print.h" 5 | # include "interrupt.h" 6 | # include "debug.h" 7 | 8 | void bitmap_init(struct bitmap* btmap) { 9 | memset(btmap->bits, 0, btmap->btmp_bytes_len); 10 | } 11 | 12 | /** 13 | * 检测指定位是否为1,如果是,返回1. 14 | */ 15 | int bitmap_scan_test(struct bitmap* btmap, uint32_t index) { 16 | uint32_t byte_index = (index / 8); 17 | uint32_t bit_odd = byte_index % 8; 18 | 19 | return (btmap->bits[byte_index] & BITMAP_MASK << bit_odd); 20 | } 21 | 22 | /** 23 | * 在位图中申请连续的cnt个位. 24 | */ 25 | int bitmap_scan(struct bitmap* btmap, uint32_t cnt) { 26 | uint32_t idx_byte = 0; 27 | 28 | // 以字节为单位进行查找 29 | while ((0xff == btmap->bits[idx_byte]) && idx_byte < btmap->btmp_bytes_len) { 30 | ++idx_byte; 31 | } 32 | 33 | // 没有找到 34 | if (idx_byte == btmap->btmp_bytes_len) { 35 | return -1; 36 | } 37 | 38 | // 找到了一个字节不全为1,那么在字节内部再次进行查找具体的起使位 39 | int idx_bit = 0; 40 | while ((uint8_t) BITMAP_MASK << idx_bit & btmap->bits[idx_byte]) { 41 | ++idx_bit; 42 | } 43 | 44 | // 起始位 45 | int bit_idx_start = (idx_byte * 8 + idx_bit); 46 | if (cnt == 1) { 47 | return bit_idx_start; 48 | } 49 | 50 | uint32_t bit_left = (btmap->btmp_bytes_len * 8 - bit_idx_start); 51 | uint32_t count = 1; 52 | 53 | uint32_t next_bit = bit_idx_start + 1; 54 | 55 | bit_idx_start = -1; 56 | while (bit_left-- > 0) { 57 | if (!(bitmap_scan_test(btmap, next_bit))) { 58 | ++count; 59 | } else { 60 | count = 0; 61 | } 62 | 63 | if (count == cnt) { 64 | bit_idx_start = (next_bit - cnt + 1); 65 | break; 66 | } 67 | 68 | next_bit++; 69 | } 70 | 71 | return bit_idx_start; 72 | } 73 | 74 | void bitmap_set(struct bitmap* btmap, uint32_t index, int8_t value) { 75 | ASSERT(value == 0 || value == 1); 76 | 77 | uint32_t byte_index = index / 8; 78 | uint32_t bit_odd = index % 8; 79 | 80 | if (value) { 81 | btmap->bits[byte_index] |= (BITMAP_MASK << bit_odd); 82 | } else { 83 | btmap->bits[byte_index] &= ~(BITMAP_MASK << bit_odd); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/lib/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_KERNEL_BITMAP_H 2 | #define _LIB_KERNEL_BITMAP_H 3 | 4 | # include "global.h" 5 | 6 | # define BITMAP_MASK 1 7 | 8 | struct bitmap { 9 | uint32_t btmp_bytes_len; 10 | uint8_t* bits; 11 | }; 12 | 13 | void bitmap_init(struct bitmap* btmap); 14 | 15 | int bitmap_scan_test(struct bitmap* btmap, uint32_t bit_idx); 16 | 17 | int bitmap_scan(struct bitmap* btmap, uint32_t cnt); 18 | 19 | void bitmap_set(struct bitmap* btmap, uint32_t index, int8_t value); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/lib/kernel/list.h: -------------------------------------------------------------------------------- 1 | # ifndef _LIB_KERNEL_LIST_H 2 | # define _LIB_KERNEL_LIST_H 3 | 4 | # include "global.h" 5 | 6 | /** 7 | * 获取结构体内成员在结构体的偏移. 8 | */ 9 | # define offset(struct_type, member) (int) (&((struct_type*)0)->member) 10 | 11 | # define elem2entry(struct_type, struct_member_name, elem_ptr) \ 12 | (struct_type*) ((int) elem_ptr - offset(struct_type, struct_member_name)) 13 | 14 | /** 15 | * 链表节点. 16 | */ 17 | struct list_elem { 18 | struct list_elem* prev; 19 | struct list_elem* next; 20 | }; 21 | 22 | /** 23 | * 链表结构. 24 | */ 25 | struct list { 26 | struct list_elem head; 27 | struct list_elem tail; 28 | }; 29 | 30 | /** 31 | * 用于链表遍历的回调函数. 32 | */ 33 | typedef int (function) (struct list_elem*, int arg); 34 | 35 | void list_init(struct list* list); 36 | void list_insert_before(struct list_elem* before, struct list_elem* elem); 37 | void list_push(struct list* list, struct list_elem* elem); 38 | void list_append(struct list* list, struct list_elem* elem); 39 | void list_remove(struct list_elem* elem); 40 | struct list_elem* list_pop(struct list* list); 41 | int list_find(struct list* list, struct list_elem* elem); 42 | int list_empty(struct list* list); 43 | uint32_t list_length(struct list* list); 44 | struct list_elem* list_traversal(struct list* list, function func, int arg); 45 | 46 | # endif -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 为print.asm提供方便引用的头文件定义. 3 | */ 4 | # ifndef _LIB_KERNEL_PRINT_H 5 | # define _LIB_KERNEL_PRINT_H 6 | 7 | # include "stdint.h" 8 | 9 | void put_char(uint8_t char_asci); 10 | 11 | /** 12 | * 字符串打印,必须以\0结尾. 13 | */ 14 | void put_str(char* message); 15 | 16 | /** 17 | * 以16进制的形式打印数字. 18 | */ 19 | void put_int(uint32_t num); 20 | 21 | void set_cursor(uint32_t pos); 22 | 23 | # endif -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/lib/stdint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 仿照/usr/include/stdint.h定义我们自己的数据类型. 3 | */ 4 | #ifndef _LIB_STDINT_H 5 | #define _LIB_STDINT_H 6 | 7 | typedef signed char int8_t; 8 | typedef signed short int int16_t; 9 | typedef signed int int32_t; 10 | typedef signed long long int int64_t; 11 | 12 | typedef unsigned char uint8_t; 13 | typedef unsigned short int uint16_t; 14 | typedef unsigned int uint32_t; 15 | typedef unsigned long long int uint64_t; 16 | 17 | #endif -------------------------------------------------------------------------------- /chapter10/terminal_with_lock/lib/string.h: -------------------------------------------------------------------------------- 1 | # ifndef _LIB_STRING_H 2 | # define _LIB_STRING_H 3 | 4 | # include "global.h" 5 | # include "debug.h" 6 | 7 | void memset(void* address, uint8_t value, uint32_t size); 8 | void memcpy(void* dst, const void* src, uint32_t size); 9 | int memcmp(const void* left, const void* right, uint32_t size); 10 | char* strcpy(char* dst, const char* src); 11 | uint32_t strlen(const char* str); 12 | int8_t strcmp(const char* left, const char* right); 13 | char* strchr(const char* str, const uint8_t c); 14 | char* strrchr(const char* str, const uint8_t c); 15 | char* strcat(char* dst, const char* src); 16 | uint32_t strchrs(const char* str, const uint8_t c); 17 | 18 | # endif -------------------------------------------------------------------------------- /chapter11/bochsrc.bxrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 启动方式 7 | boot: disk 8 | 9 | # 关闭鼠标 10 | mouse: enabled=0 11 | 12 | # 硬盘设置 13 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 14 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 15 | -------------------------------------------------------------------------------- /chapter11/device/console.c: -------------------------------------------------------------------------------- 1 | # include "console.h" 2 | # include "kernel/print.h" 3 | # include "stdint.h" 4 | # include "thread/sync.h" 5 | # include "thread/thread.h" 6 | 7 | static struct lock console_lock; 8 | 9 | void console_init() { 10 | lock_init(&console_lock); 11 | } 12 | 13 | void console_acquire() { 14 | lock_acquire(&console_lock); 15 | } 16 | 17 | void console_release() { 18 | lock_release(&console_lock); 19 | } 20 | 21 | void console_put_str(char* str) { 22 | console_acquire(); 23 | put_str(str); 24 | console_release(); 25 | } 26 | 27 | void console_put_char(uint8_t char_asci) { 28 | console_acquire(); 29 | put_char(char_asci); 30 | console_release(); 31 | } 32 | 33 | void console_put_int(uint32_t num) { 34 | console_acquire(); 35 | put_int(num); 36 | console_release(); 37 | } -------------------------------------------------------------------------------- /chapter11/device/console.h: -------------------------------------------------------------------------------- 1 | # ifndef _DEVICE_CONSOLE_H 2 | # define _DEVICE_CONSOLE_H 3 | 4 | # include "stdint.h" 5 | 6 | void console_init(); 7 | void console_acquire(); 8 | void console_release(); 9 | void console_put_str(char* str); 10 | void console_put_char(uint8_t char_asci); 11 | void console_put_int(uint32_t num); 12 | 13 | # endif -------------------------------------------------------------------------------- /chapter11/device/ioqueue.c: -------------------------------------------------------------------------------- 1 | # include "ioqueue.h" 2 | # include "interrupt.h" 3 | # include "global.h" 4 | # include "debug.h" 5 | 6 | void ioqueue_init(struct ioqueue* queue) { 7 | lock_init(&queue->lock); 8 | queue->head = queue->tail = 0; 9 | queue->producer = queue->tail = NULL; 10 | } 11 | 12 | static int32_t next_pos(int32_t pos) { 13 | return (pos + 1) % buf_size; 14 | } 15 | 16 | int is_queue_full(struct ioqueue* queue) { 17 | return next_pos(queue->head) == queue->tail; 18 | } 19 | 20 | int is_queue_empty(struct ioqueue* queue) { 21 | return queue->head == queue->tail; 22 | } 23 | 24 | static void queue_wait(struct task_struct** waiter) { 25 | *waiter = running_thread(); 26 | thread_block(TASK_BLOCKED); 27 | } 28 | 29 | static void wakeup(struct task_struct** waiter) { 30 | thread_unblock(*waiter); 31 | *waiter = NULL; 32 | } 33 | 34 | /** 35 | * 从给定的队列中获取一个字符,如果队列为空,那么等待. 36 | */ 37 | char queue_getchar(struct ioqueue* queue) { 38 | ASSERT(intr_get_status() == INTR_OFF); 39 | 40 | while (is_queue_empty(queue)) { 41 | lock_acquire(&queue->lock); 42 | // 这里同时会把ioqueue的consumer置为当前线程 43 | queue_wait(&queue->consumer); 44 | lock_release(&queue->lock); 45 | } 46 | 47 | char byte = queue->buf[queue->tail]; 48 | queue->tail = next_pos(queue->tail); 49 | 50 | if (queue->producer != NULL) { 51 | // 在无锁的情况下调用解除阻塞操作,因为bochs是单核CPU且屏蔽了中断,所以是安全的 52 | wakeup(&queue->producer); 53 | } 54 | 55 | return byte; 56 | } 57 | 58 | char queue_putchar(struct ioqueue* queue, char byte) { 59 | ASSERT(intr_get_status() == INTR_OFF); 60 | 61 | while (is_queue_full(queue)) { 62 | lock_acquire(&queue->lock); 63 | queue_wait(&queue->producer); 64 | lock_release(&queue->lock); 65 | } 66 | 67 | queue->buf[queue->head] = byte; 68 | queue->head = next_pos(queue->head); 69 | 70 | if (queue->consumer != NULL) { 71 | wakeup(&queue->consumer); 72 | } 73 | } -------------------------------------------------------------------------------- /chapter11/device/ioqueue.h: -------------------------------------------------------------------------------- 1 | # ifndef _DEVICE_IOQUEUE_H 2 | # define _DEVICE_IOQUEUE_H 3 | 4 | # include "stdint.h" 5 | # include "thread/thread.h" 6 | # include "thread/sync.h" 7 | 8 | # define buf_size 64 9 | 10 | struct ioqueue { 11 | // 感觉这个锁然并卵 12 | struct lock* lock; 13 | struct task_struct* producer; 14 | struct task_struct* consumer; 15 | char buf[buf_size]; 16 | int32_t head; 17 | int32_t tail; 18 | }; 19 | 20 | int is_queue_full(struct ioqueue* queue); 21 | void ioqueue_init(struct ioqueue* queue); 22 | int is_queue_empty(struct ioqueue* queue); 23 | char queue_getchar(struct ioqueue* queue); 24 | char queue_putchar(struct ioqueue* queue, char byte); 25 | 26 | # endif -------------------------------------------------------------------------------- /chapter11/device/keyboard.h: -------------------------------------------------------------------------------- 1 | # ifndef _DEVICE_KEYBOARD_H 2 | # define _DEVICE_KEYBOARD_H 3 | 4 | void keyboard_init(void); 5 | 6 | # endif -------------------------------------------------------------------------------- /chapter11/device/timer.c: -------------------------------------------------------------------------------- 1 | # include "io.h" 2 | # include "kernel/print.h" 3 | # include "interrupt.h" 4 | # include "thread/thread.h" 5 | # include "debug.h" 6 | 7 | # define IRQ0_FREQUENCY 1000 8 | # define INPUT_FREQUENCY 1193180 9 | # define COUNTER0_VALUE INPUT_FREQUENCY / IRQ0_FREQUENCY 10 | # define COUNTER0_PORT 0x40 11 | # define COUNTER_MODE 2 12 | # define COUNTER0_NO 0 13 | # define READ_WRITE_LATCH 3 14 | # define PIT_CONTROL_PORT 0x43 15 | 16 | /** 17 | * 内核自开启中断后所有的嘀嗒数. 18 | */ 19 | uint32_t ticks; 20 | 21 | static void frequency_set(uint8_t counter_port, 22 | uint8_t counter_no, 23 | uint8_t rwl, 24 | uint8_t counter_mode, 25 | uint16_t counter_value) { 26 | outb(PIT_CONTROL_PORT, (uint8_t) (counter_no << 6 | rwl << 4 | counter_mode << 1)); 27 | outb(counter_port, (uint8_t) counter_value); 28 | outb(counter_port, (uint8_t) counter_value >> 8); 29 | } 30 | 31 | static void intr_timer_handler(void) { 32 | struct task_struct* cur_thread = running_thread(); 33 | 34 | ASSERT(cur_thread->stack_magic == 0x77777777); 35 | 36 | cur_thread->elaspsed_ticks++; 37 | ticks++; 38 | 39 | if (cur_thread->ticks == 0) { 40 | schedule(); 41 | } else { 42 | cur_thread->ticks--; 43 | } 44 | } 45 | 46 | /** 47 | * 初始化PIT 8253. 48 | */ 49 | void timer_init() { 50 | put_str("timer_init start.\n"); 51 | frequency_set(COUNTER0_PORT, COUNTER0_NO, READ_WRITE_LATCH, COUNTER_MODE, COUNTER0_VALUE); 52 | register_handler(0x20, intr_timer_handler); 53 | put_str("timer_init done.\n"); 54 | } -------------------------------------------------------------------------------- /chapter11/device/timer.h: -------------------------------------------------------------------------------- 1 | void timer_init(); -------------------------------------------------------------------------------- /chapter11/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_START_SECTOR equ 0x9 6 | KERNEL_BIN_BASE_ADDR equ 0x70000 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ; gdt描述符属性 10 | ; 段描述符高23位,表示段界限的粒度为4KB 11 | DESC_G_4K equ 100000000000000000000000b 12 | 13 | ; D/B为,1表示运行在32位模式下 14 | DESC_D_32 equ 10000000000000000000000b 15 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 16 | DESC_L equ 0000000000000000000000b 17 | ; 没有明确的用途,取值随意 18 | DESC_AVL equ 000000000000000000000b 19 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 20 | DESC_LIMIT_CODE2 equ 11110000000000000000b 21 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 22 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 23 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 24 | DESC_P equ 1000000000000000b 25 | DESC_DPL_0 equ 000000000000000b 26 | DESC_DPL_1 equ 010000000000000b 27 | DESC_DPL_2 equ 100000000000000b 28 | DESC_DPL_3 equ 110000000000000b 29 | DESC_S_CODE equ 1000000000000b 30 | DESC_S_DATA equ DESC_S_CODE 31 | DESC_S_sys equ 0000000000000b 32 | DESC_TYPE_CODE equ 100000000000b 33 | DESC_TYPE_DATA equ 001000000000b 34 | 35 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 36 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 39 | 40 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 45 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 46 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 47 | 48 | ; 选择字属性 49 | RPL0 equ 00b 50 | RPL1 equ 01b 51 | RPL2 equ 10b 52 | RPL3 equ 11b 53 | TI_GDT equ 000b 54 | TI_LDT equ 100b 55 | 56 | ; 页表相关属性 57 | PG_P equ 1b 58 | PG_RW_R equ 00b 59 | PG_RW_W equ 10b 60 | PG_US_S equ 000b 61 | PG_US_U equ 100b 62 | 63 | PT_NULL equ 0 -------------------------------------------------------------------------------- /chapter11/kernel/debug.c: -------------------------------------------------------------------------------- 1 | # include "debug.h" 2 | # include "kernel/print.h" 3 | # include "interrupt.h" 4 | 5 | void panic_spin(char* filename, int line, const char* func, const char* condition) { 6 | intr_disable(); 7 | 8 | put_str("Something wrong..."); 9 | 10 | put_str("FileName: "); 11 | put_str(filename); 12 | put_char('\n'); 13 | 14 | put_str("Line: "); 15 | put_int(line); 16 | put_char('\n'); 17 | 18 | put_str("Function: "); 19 | put_str(func); 20 | put_char('\n'); 21 | 22 | put_str("Condition: "); 23 | put_str(condition); 24 | put_char('\n'); 25 | 26 | while (1); 27 | } -------------------------------------------------------------------------------- /chapter11/kernel/debug.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_DEBUG_H 2 | # define _KERNEL_DEBUG_H 3 | 4 | void panic_spin(char* filename, int line, const char* func, const char* condition); 5 | 6 | /** 7 | * 当断言被触发时调用. 8 | * _FILE_: 内置宏,表示调用的文件名 9 | * _LINE_: 内置宏,被编译文件的行号 10 | * _func_: 内置宏: 被编译的函数名 11 | * _VA_ARGS_: 函数调用参数 12 | */ 13 | # define PANIC(...) panic_spin (__FILE__, __LINE__, __func__, __VA_ARGS__) 14 | 15 | # ifdef NDEBUG 16 | # define ASSERT(CONDITION) ((void) 0) 17 | # else 18 | # define ASSERT(CONDITION) \ 19 | if (CONDITION) { \ 20 | } else { \ 21 | PANIC(#CONDITION); \ 22 | } 23 | # endif 24 | # endif -------------------------------------------------------------------------------- /chapter11/kernel/init.c: -------------------------------------------------------------------------------- 1 | # include "init.h" 2 | # include "kernel/print.h" 3 | # include "timer.h" 4 | # include "memory.h" 5 | # include "thread/thread.h" 6 | # include "console.h" 7 | # include "keyboard.h" 8 | # include "tss.h" 9 | 10 | void init_all() { 11 | put_str("init_all.\n"); 12 | idt_init(); 13 | mem_init(); 14 | thread_init(); 15 | timer_init(); 16 | console_init(); 17 | keyboard_init(); 18 | tss_init(); 19 | } -------------------------------------------------------------------------------- /chapter11/kernel/init.h: -------------------------------------------------------------------------------- 1 | void init_all(void); -------------------------------------------------------------------------------- /chapter11/kernel/interrupt.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_INTERRUPT_H 2 | # define _KERNEL_INTERRUPT_H 3 | 4 | # include "stdint.h" 5 | 6 | typedef void* intr_handler; 7 | 8 | void idt_init(void); 9 | 10 | /** 11 | * 中断状态. 12 | */ 13 | enum intr_status { 14 | INTR_OFF, 15 | INTR_ON 16 | }; 17 | 18 | enum intr_status intr_get_status(void); 19 | enum intr_status intr_set_status(enum intr_status); 20 | enum intr_status intr_enable(void); 21 | enum intr_status intr_disable(void); 22 | void register_handler(uint8_t vec_no, intr_handler handler); 23 | 24 | # endif 25 | -------------------------------------------------------------------------------- /chapter11/kernel/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_IO_H 2 | # define _LIB_IO_H 3 | 4 | # include "stdint.h" 5 | 6 | /** 7 | * 向指定的端口写入一个字节的数据. 8 | */ 9 | static inline void outb(uint16_t port, uint8_t data) { 10 | asm volatile ("outb %b0, %w1" : : "a" (data), "Nd" (port)); 11 | } 12 | 13 | /** 14 | * 将addr起始处的word_cnt个字节写入端口port. 15 | */ 16 | static inline void outsw(uint16_t port, const void* addr, uint32_t word_cnt) { 17 | asm volatile ("cld; rep outsw" : "+S" (addr), "+c" (word_cnt) : "d" (port)); 18 | } 19 | 20 | /** 21 | * 将从端口port读入的一个字节返回. 22 | */ 23 | static inline uint8_t inb(uint16_t port) { 24 | uint8_t data; 25 | asm volatile ("inb %w1, %b0" : "=a" (data) : "Nd" (port)); 26 | return data; 27 | } 28 | 29 | /** 30 | * 将从port读取的word_cnt字节写入addr. 31 | */ 32 | static inline void insw(uint16_t port, void* addr, uint32_t word_cnt) { 33 | asm volatile ("cld; rep insw" : "+D" (addr), "+c" (word_cnt) : "d" (port) : "memory"); 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /chapter11/kernel/kernel.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ; 对于CPU会自动压入错误码的中断类型,无需额外的操作 4 | %define ERROR_CODE nop 5 | ; 如果CPU没有压入错误码,为了保持处理逻辑的一致性,我们需要手动压入一个0 6 | %define ZERO push 0 7 | 8 | extern put_str 9 | ; 中断处理函数数组 10 | extern idt_table 11 | 12 | section .data 13 | intr_str db "interrupt occur!", 0xa, 0 14 | global intr_entry_table 15 | intr_entry_table: 16 | 17 | ; 中断处理程序宏定义 18 | %macro VECTOR 2 19 | section .text 20 | intr%1entry: 21 | 22 | %2 23 | ; 保存上下文 24 | push ds 25 | push es 26 | push fs 27 | push gs 28 | pushad 29 | 30 | mov al, 0x20 31 | out 0xa0, al 32 | out 0x20, al 33 | 34 | push %1 35 | 36 | ; 调用C的中断处理函数 37 | call [idt_table + 4 * %1] 38 | jmp intr_exit 39 | 40 | section .data 41 | dd intr%1entry 42 | 43 | %endmacro 44 | 45 | section .text 46 | global intr_exit 47 | intr_exit: 48 | add esp, 4 49 | popad 50 | pop gs 51 | pop fs 52 | pop es 53 | pop ds 54 | add esp, 4 55 | iretd 56 | 57 | VECTOR 0x00, ZERO 58 | VECTOR 0x01, ZERO 59 | VECTOR 0x02, ZERO 60 | VECTOR 0x03, ZERO 61 | VECTOR 0x04, ZERO 62 | VECTOR 0x05, ZERO 63 | VECTOR 0x06, ZERO 64 | VECTOR 0x07, ZERO 65 | VECTOR 0x08, ZERO 66 | VECTOR 0x09, ZERO 67 | VECTOR 0x0a, ZERO 68 | VECTOR 0x0b, ZERO 69 | VECTOR 0x0c, ZERO 70 | VECTOR 0x0d, ZERO 71 | VECTOR 0x0e, ZERO 72 | VECTOR 0x0f, ZERO 73 | VECTOR 0x10, ZERO 74 | VECTOR 0x11, ZERO 75 | VECTOR 0x12, ZERO 76 | VECTOR 0x13, ZERO 77 | VECTOR 0x14, ZERO 78 | VECTOR 0x15, ZERO 79 | VECTOR 0x16, ZERO 80 | VECTOR 0x17, ZERO 81 | VECTOR 0x18, ZERO 82 | VECTOR 0x19, ZERO 83 | VECTOR 0x1a, ZERO 84 | VECTOR 0x1b, ZERO 85 | VECTOR 0x1c, ZERO 86 | VECTOR 0x1d, ZERO 87 | VECTOR 0x1e, ERROR_CODE 88 | VECTOR 0x1f, ZERO 89 | VECTOR 0x20, ZERO 90 | VECTOR 0x21, ZERO 91 | VECTOR 0x22, ZERO 92 | VECTOR 0x23, ZERO 93 | VECTOR 0x24, ZERO 94 | VECTOR 0x25, ZERO 95 | VECTOR 0x26, ZERO 96 | VECTOR 0x27, ZERO 97 | VECTOR 0x28, ZERO 98 | VECTOR 0x29, ZERO 99 | VECTOR 0x2a, ZERO 100 | VECTOR 0x2b, ZERO 101 | VECTOR 0x2c, ZERO 102 | VECTOR 0x2d, ZERO 103 | VECTOR 0x2e, ZERO 104 | VECTOR 0x2f, ZERO -------------------------------------------------------------------------------- /chapter11/kernel/main.c: -------------------------------------------------------------------------------- 1 | # include "kernel/print.h" 2 | # include "init.h" 3 | # include "interrupt.h" 4 | # include "process.h" 5 | 6 | void k_thread_function_a(void); 7 | void k_thread_function_b(void); 8 | void user_process_a(void); 9 | void user_process_b(void); 10 | int test_var_a = 0, test_var_b = 0; 11 | 12 | int main(void) { 13 | // 这里不能使用console_put_str,因为还没有初始化 14 | put_str("I am kernel.\n"); 15 | init_all(); 16 | 17 | thread_start("k_thread_a", default_prio, k_thread_function_a, "threadA "); 18 | thread_start("k_thread_b", default_prio, k_thread_function_b, "threadB "); 19 | process_execute(user_process_a, "user_process_a"); 20 | process_execute(user_process_b, "user_process_b"); 21 | 22 | intr_enable(); 23 | 24 | while (1); 25 | 26 | return 0; 27 | } 28 | 29 | void k_thread_function_a(void) { 30 | while (1) { 31 | console_put_str("v_a: 0x"); 32 | console_put_int(test_var_a); 33 | } 34 | } 35 | 36 | void k_thread_function_b(void) { 37 | while (1) { 38 | console_put_str("v_b: 0x"); 39 | console_put_int(test_var_b); 40 | } 41 | } 42 | 43 | void user_process_a(void) { 44 | while (1) { 45 | test_var_a++; 46 | } 47 | } 48 | 49 | void user_process_b(void) { 50 | while (1) { 51 | test_var_b++; 52 | } 53 | } -------------------------------------------------------------------------------- /chapter11/kernel/memory.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_MEMORY_H 2 | # define _KERNEL_MEMORY_H 3 | 4 | # include "stdint.h" 5 | # include "bitmap.h" 6 | 7 | // 存在标志 8 | # define PG_P_1 1 9 | # define PG_P_0 0 10 | // 只读 11 | # define PG_RW_R 0 12 | // 可写 13 | # define PG_RW_W 2 14 | // 系统级 15 | # define PG_US_S 0 16 | # define PG_US_U 4 17 | 18 | /** 19 | * 内存池类型标志. 20 | */ 21 | enum pool_flags { 22 | // 内核类型 23 | PF_KERNEL = 1, 24 | PF_USER = 2 25 | }; 26 | 27 | struct virtual_addr { 28 | struct bitmap vaddr_bitmap; 29 | // 虚拟内存的起始地址 30 | uint32_t vaddr_start; 31 | }; 32 | 33 | extern struct pool kernel_pool, user_pool; 34 | 35 | void mem_init(void); 36 | void* get_kernel_pages(uint32_t page_count); 37 | void* malloc_page(enum pool_flags pf, uint32_t page_count); 38 | uint32_t addr_v2p(uint32_t vaddr); 39 | void* get_a_page(enum pool_flags pf, uint32_t vaddr); 40 | void* get_user_pages(uint32_t page_count); 41 | 42 | # endif -------------------------------------------------------------------------------- /chapter11/kernel/switch.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | section .text 3 | global switch_to 4 | switch_to: 5 | ; 将中断处理函数的上下文保存到目标PCB的栈中 6 | ; 这里隐含的是下次调度返回的地址其实是switch_to的返回地址 7 | push esi 8 | push edi 9 | push ebx 10 | push ebp 11 | mov eax, [esp + 20] 12 | mov [eax], esp 13 | 14 | ; 跳到目标PCB执行 15 | mov eax, [esp + 24] 16 | mov esp, [eax] 17 | pop ebp 18 | pop ebx 19 | pop edi 20 | pop esi 21 | ret -------------------------------------------------------------------------------- /chapter11/kernel/thread/sync.c: -------------------------------------------------------------------------------- 1 | # include "sync.h" 2 | # include "interrupt.h" 3 | # include "debug.h" 4 | 5 | void semaphore_init(struct semaphore* psem, uint8_t value) { 6 | psem->value = value; 7 | list_init(&psem->waiters); 8 | } 9 | 10 | void lock_init(struct lock* lock) { 11 | lock->holder = NULL; 12 | lock->holder_repeat_num = 0; 13 | semaphore_init(&lock->semaphore, 1); 14 | } 15 | 16 | void semaphore_down(struct semaphore* psem) { 17 | enum intr_status old_status = intr_disable(); 18 | 19 | while (psem->value == 0) { 20 | struct task_struct* cur = running_thread(); 21 | ASSERT(!list_find(&psem->waiters, &cur->general_tag)); 22 | list_append(&psem->waiters, &cur->general_tag); 23 | thread_block(TASK_BLOCKED); 24 | } 25 | 26 | psem->value--; 27 | ASSERT(psem->value == 0); 28 | intr_set_status(old_status); 29 | } 30 | 31 | void semaphore_up(struct semaphore* psem) { 32 | enum intr_status old_status = intr_disable(); 33 | ASSERT(psem->value == 0); 34 | 35 | if (!list_empty(&psem->waiters)) { 36 | struct task_struct* waiter = elem2entry(struct task_struct, general_tag, list_pop(&psem->waiters)); 37 | thread_unblock(waiter); 38 | } 39 | 40 | psem->value++; 41 | ASSERT(psem->value == 1); 42 | intr_set_status(old_status); 43 | } 44 | 45 | /** 46 | * 申请锁. 47 | */ 48 | void lock_acquire(struct lock* plock) { 49 | struct task_struct* cur = running_thread(); 50 | if (plock->holder != cur) { 51 | semaphore_down(&plock->semaphore); 52 | plock->holder = cur; 53 | ASSERT(plock->holder_repeat_num == 0); 54 | plock->holder_repeat_num = 1; 55 | } else { 56 | plock->holder_repeat_num++; 57 | } 58 | } 59 | 60 | /** 61 | * 锁释放. 62 | */ 63 | void lock_release(struct lock* plock) { 64 | ASSERT(plock->holder == running_thread()); 65 | 66 | if (plock->holder_repeat_num > 1) { 67 | plock->holder_repeat_num--; 68 | return; 69 | } 70 | 71 | ASSERT(plock->holder_repeat_num == 1); 72 | 73 | plock->holder = NULL; 74 | plock->holder_repeat_num = 0; 75 | semaphore_up(&plock->semaphore); 76 | } -------------------------------------------------------------------------------- /chapter11/kernel/thread/sync.h: -------------------------------------------------------------------------------- 1 | # ifndef _THREAD_SYNC_H 2 | # define _THREAD_SYNC_H 3 | 4 | # include "kernel/list.h" 5 | # include "thread.h" 6 | # include "stdint.h" 7 | 8 | /** 9 | * 信号量. 10 | */ 11 | struct semaphore { 12 | uint8_t value; 13 | struct list waiters; 14 | }; 15 | 16 | struct lock { 17 | struct task_struct* holder; 18 | struct semaphore semaphore; 19 | uint32_t holder_repeat_num; 20 | }; 21 | 22 | void semaphore_init(struct semaphore* psem, uint8_t value); 23 | void lock_init(struct lock* lock); 24 | void semaphore_down(struct semaphore* psem); 25 | void semaphore_up(struct semaphore* psem); 26 | void lock_acquire(struct lock* plock); 27 | void lock_release(struct lock* plock); 28 | 29 | # endif -------------------------------------------------------------------------------- /chapter11/lib/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_KERNEL_BITMAP_H 2 | #define _LIB_KERNEL_BITMAP_H 3 | 4 | # include "global.h" 5 | 6 | # define BITMAP_MASK 1 7 | 8 | struct bitmap { 9 | uint32_t btmp_bytes_len; 10 | uint8_t* bits; 11 | }; 12 | 13 | void bitmap_init(struct bitmap* btmap); 14 | 15 | int bitmap_scan_test(struct bitmap* btmap, uint32_t bit_idx); 16 | 17 | int bitmap_scan(struct bitmap* btmap, uint32_t cnt); 18 | 19 | void bitmap_set(struct bitmap* btmap, uint32_t index, int8_t value); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /chapter11/lib/kernel/list.h: -------------------------------------------------------------------------------- 1 | # ifndef _LIB_KERNEL_LIST_H 2 | # define _LIB_KERNEL_LIST_H 3 | 4 | # include "global.h" 5 | 6 | /** 7 | * 获取结构体内成员在结构体的偏移. 8 | */ 9 | # define offset(struct_type, member) (int) (&((struct_type*)0)->member) 10 | 11 | # define elem2entry(struct_type, struct_member_name, elem_ptr) \ 12 | (struct_type*) ((int) elem_ptr - offset(struct_type, struct_member_name)) 13 | 14 | /** 15 | * 链表节点. 16 | */ 17 | struct list_elem { 18 | struct list_elem* prev; 19 | struct list_elem* next; 20 | }; 21 | 22 | /** 23 | * 链表结构. 24 | */ 25 | struct list { 26 | struct list_elem head; 27 | struct list_elem tail; 28 | }; 29 | 30 | /** 31 | * 用于链表遍历的回调函数. 32 | */ 33 | typedef int (function) (struct list_elem*, int arg); 34 | 35 | void list_init(struct list* list); 36 | void list_insert_before(struct list_elem* before, struct list_elem* elem); 37 | void list_push(struct list* list, struct list_elem* elem); 38 | void list_append(struct list* list, struct list_elem* elem); 39 | void list_remove(struct list_elem* elem); 40 | struct list_elem* list_pop(struct list* list); 41 | int list_find(struct list* list, struct list_elem* elem); 42 | int list_empty(struct list* list); 43 | uint32_t list_length(struct list* list); 44 | struct list_elem* list_traversal(struct list* list, function func, int arg); 45 | 46 | # endif -------------------------------------------------------------------------------- /chapter11/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 为print.asm提供方便引用的头文件定义. 3 | */ 4 | # ifndef _LIB_KERNEL_PRINT_H 5 | # define _LIB_KERNEL_PRINT_H 6 | 7 | # include "stdint.h" 8 | 9 | void put_char(uint8_t char_asci); 10 | 11 | /** 12 | * 字符串打印,必须以\0结尾. 13 | */ 14 | void put_str(char* message); 15 | 16 | /** 17 | * 以16进制的形式打印数字. 18 | */ 19 | void put_int(uint32_t num); 20 | 21 | void set_cursor(uint32_t pos); 22 | 23 | # endif -------------------------------------------------------------------------------- /chapter11/lib/stdint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 仿照/usr/include/stdint.h定义我们自己的数据类型. 3 | */ 4 | #ifndef _LIB_STDINT_H 5 | #define _LIB_STDINT_H 6 | 7 | typedef signed char int8_t; 8 | typedef signed short int int16_t; 9 | typedef signed int int32_t; 10 | typedef signed long long int int64_t; 11 | 12 | typedef unsigned char uint8_t; 13 | typedef unsigned short int uint16_t; 14 | typedef unsigned int uint32_t; 15 | typedef unsigned long long int uint64_t; 16 | 17 | #endif -------------------------------------------------------------------------------- /chapter11/lib/string.h: -------------------------------------------------------------------------------- 1 | # ifndef _LIB_STRING_H 2 | # define _LIB_STRING_H 3 | 4 | # include "global.h" 5 | # include "debug.h" 6 | 7 | void memset(void* address, uint8_t value, uint32_t size); 8 | void memcpy(void* dst, const void* src, uint32_t size); 9 | int memcmp(const void* left, const void* right, uint32_t size); 10 | char* strcpy(char* dst, const char* src); 11 | uint32_t strlen(const char* str); 12 | int8_t strcmp(const char* left, const char* right); 13 | char* strchr(const char* str, const uint8_t c); 14 | char* strrchr(const char* str, const uint8_t c); 15 | char* strcat(char* dst, const char* src); 16 | uint32_t strchrs(const char* str, const uint8_t c); 17 | 18 | # endif -------------------------------------------------------------------------------- /chapter11/user/process.h: -------------------------------------------------------------------------------- 1 | # ifndef _USER_PROCESS_H 2 | 3 | # include "thread/thread.h" 4 | 5 | # define _USER_PROCESS_H 6 | 7 | # define USER_STACK3_VADDR (0xc0000000 - 0x1000) 8 | # define USER_VADDR_START 0x8048000 9 | # define default_prio 31 10 | 11 | void start_process(void* filename); 12 | void page_dir_activate(struct task_struct* pthread); 13 | void process_activate(struct task_struct* pthread); 14 | void create_user_vaddr_bitmap(struct task_struct* user_process); 15 | void process_execute(void* filename, char* name); 16 | 17 | # endif -------------------------------------------------------------------------------- /chapter11/user/tss.h: -------------------------------------------------------------------------------- 1 | # ifndef _USER_TSS_H 2 | # define _USER_TSS_H 3 | 4 | void update_tss_esp(struct task_struct* pthread); 5 | void tss_init(); 6 | 7 | # endif -------------------------------------------------------------------------------- /chapter3/bochsrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 对应真实机器的bios 7 | romimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/BIOS-bochs-latest 8 | # 对应真实机器的VGA bios 9 | vgaromimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/VGABIOS-lgpl-latest 10 | 11 | # 启动方式 12 | boot: disk 13 | 14 | # 关闭鼠标 15 | mouse: enabled=0 16 | 17 | # 硬盘设置 18 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 19 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 20 | -------------------------------------------------------------------------------- /chapter3/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Creating disk.img..." 4 | bximage -mode=create -hd=10M -q disk.img 5 | 6 | echo "Compiling..." 7 | nasm -I include/ -o mbr.bin mbr.asm 8 | nasm -I include/ -o loader.bin loader.asm 9 | 10 | echo "Writing mbr and loader to disk..." 11 | dd if=mbr.bin of=disk.img bs=512 count=1 conv=notrunc 12 | dd if=loader.bin of=disk.img bs=512 count=1 seek=2 conv=notrunc 13 | 14 | echo "Now start bochs and have fun!" 15 | bochs -f bochsrc 16 | -------------------------------------------------------------------------------- /chapter3/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f disk.img *.bin 4 | -------------------------------------------------------------------------------- /chapter3/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 -------------------------------------------------------------------------------- /chapter3/loader.asm: -------------------------------------------------------------------------------- 1 | %include "boot.inc" 2 | 3 | section loader vstart=LOADER_BASE_ADDR 4 | 5 | ; 简单的输出跳动的字符串 "1 MBR" 6 | mov byte [gs:0x00], '2' 7 | mov byte [gs:0x01], 0xA4 8 | 9 | mov byte [gs:0x02], ' ' 10 | mov byte [gs:0x03], 0xA4 11 | 12 | mov byte [gs:0x04], 'L' 13 | mov byte [gs:0x05], 0xA4 14 | 15 | mov byte [gs:0x06], 'O' 16 | mov byte [gs:0x07], 0xA4 17 | 18 | mov byte [gs:0x08], 'A' 19 | mov byte [gs:0x09], 0xA4 20 | 21 | mov byte [gs:0x0a], 'D' 22 | mov byte [gs:0x0b], 0xA4 23 | 24 | mov byte [gs:0x0c], 'E' 25 | mov byte [gs:0x0d], 0xA4 26 | 27 | mov byte [gs:0x0e], 'R' 28 | mov byte [gs:0x0f], 0xA4 29 | 30 | jmp $ -------------------------------------------------------------------------------- /chapter3/mbr.asm: -------------------------------------------------------------------------------- 1 | ; 主引导程序 2 | ;----------------------------------------------- 3 | %include "boot.inc" 4 | SECTION MBR vstart=0x7c00 5 | 6 | mov ax, cs 7 | mov ds, ax 8 | mov es, ax 9 | mov ss, ax 10 | mov fs, ax 11 | mov sp, 0x7c00 12 | mov ax, 0xb800 13 | mov gs, ax 14 | 15 | ; 清屏 16 | ;--------------------------------------------------- 17 | mov ax, 0600h 18 | mov bx, 0700h 19 | mov cx, 0 20 | mov dx, 184fh 21 | int 10h 22 | 23 | ; 显示"MBR" 24 | mov byte [gs:0x00], '1' 25 | mov byte [gs:0x01], 0xA4 26 | 27 | mov byte [gs:0x02], ' ' 28 | mov byte [gs:0x03], 0xA4 29 | 30 | mov byte [gs:0x04], 'M' 31 | mov byte [gs:0x05], 0xA4 32 | 33 | mov byte [gs:0x06], 'B' 34 | mov byte [gs:0x07], 0xA4 35 | 36 | mov byte [gs:0x08], 'A' 37 | mov byte [gs:0x09], 0xA4 38 | 39 | mov eax, LOADER_START_SECTOR 40 | mov bx, LOADER_BASE_ADDR 41 | mov cx, 1 42 | call rd_disk_m_16 43 | 44 | jmp LOADER_BASE_ADDR 45 | 46 | ;----------------------------------------------------------- 47 | ; 读取磁盘的n个扇区,用于加载loader 48 | ; eax保存从硬盘读取到的数据的保存地址,ebx为起始扇区,cx为读取的扇区数 49 | rd_disk_m_16: 50 | ;----------------------------------------------------------- 51 | 52 | mov esi, eax 53 | mov di, cx 54 | 55 | mov dx, 0x1f2 56 | mov al, cl 57 | out dx, al 58 | 59 | mov eax, esi 60 | 61 | mov dx, 0x1f3 62 | out dx, al 63 | 64 | mov cl, 8 65 | shr eax, cl 66 | mov dx, 0x1f4 67 | out dx, al 68 | 69 | shr eax, cl 70 | mov dx, 0x1f5 71 | out dx, al 72 | 73 | shr eax, cl 74 | and al, 0x0f 75 | or al, 0xe0 76 | mov dx, 0x1f6 77 | out dx, al 78 | 79 | mov dx, 0x1f7 80 | mov al, 0x20 81 | out dx, al 82 | 83 | .not_ready: 84 | nop 85 | in al, dx 86 | and al, 0x88 87 | cmp al, 0x08 88 | jnz .not_ready 89 | 90 | mov ax, di 91 | mov dx, 256 92 | mul dx 93 | mov cx, ax 94 | mov dx, 0x1f0 95 | 96 | .go_on_read: 97 | in ax, dx 98 | mov [bx], ax 99 | add bx, 2 100 | loop .go_on_read 101 | ret 102 | 103 | times 510-($-$$) db 0 104 | db 0x55, 0xaa -------------------------------------------------------------------------------- /chapter4/bochsrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 对应真实机器的bios 7 | romimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/BIOS-bochs-latest 8 | # 对应真实机器的VGA bios 9 | vgaromimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/VGABIOS-lgpl-latest 10 | 11 | # 启动方式 12 | boot: disk 13 | 14 | # 关闭鼠标 15 | mouse: enabled=0 16 | 17 | # 硬盘设置 18 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 19 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 20 | -------------------------------------------------------------------------------- /chapter4/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Creating disk.img..." 4 | bximage -mode=create -hd=10M -q disk.img 5 | 6 | echo "Compiling..." 7 | nasm -I include/ -o mbr.bin mbr.asm 8 | nasm -I include/ -o loader.bin loader.asm 9 | 10 | echo "Writing mbr and loader to disk..." 11 | dd if=mbr.bin of=disk.img bs=512 count=1 conv=notrunc 12 | dd if=loader.bin of=disk.img bs=512 count=4 seek=2 conv=notrunc 13 | 14 | echo "Now start bochs and have fun!" 15 | bochs -f bochsrc -------------------------------------------------------------------------------- /chapter4/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f disk.img *.bin 4 | -------------------------------------------------------------------------------- /chapter4/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | 5 | ; gdt描述符属性 6 | ; 段描述符高23位,表示段界限的粒度为4KB 7 | DESC_G_4K equ 100000000000000000000000b 8 | 9 | ; D/B为,1表示运行在32位模式下 10 | DESC_D_32 equ 10000000000000000000000b 11 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 12 | DESC_L equ 0000000000000000000000b 13 | ; 没有明确的用途,取值随意 14 | DESC_AVL equ 000000000000000000000b 15 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 16 | DESC_LIMIT_CODE2 equ 11110000000000000000b 17 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 18 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 19 | DESC_LIMIT_VIDEO2 equ 0000000000000001011b 20 | DESC_P equ 1000000000000000b 21 | DESC_DPL_0 equ 000000000000000b 22 | DESC_DPL_1 equ 010000000000000b 23 | DESC_DPL_2 equ 100000000000000b 24 | DESC_DPL_3 equ 110000000000000b 25 | DESC_S_CODE equ 1000000000000b 26 | DESC_S_DATA equ DESC_S_CODE 27 | DESC_S_sys equ 0000000000000b 28 | DESC_TYPE_CODE equ 100000000000b 29 | DESC_TYPE_DATA equ 001000000000b 30 | 31 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 32 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 33 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 34 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 35 | 36 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 39 | 40 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | ; 选择字属性 45 | RPL0 equ 00b 46 | RPL1 equ 01b 47 | RPL2 equ 10b 48 | RPL3 equ 11b 49 | TI_GDT equ 000b 50 | TI_LDT equ 100b 51 | -------------------------------------------------------------------------------- /chapter4/loader.asm: -------------------------------------------------------------------------------- 1 | %include "boot.inc" 2 | 3 | section loader vstart=LOADER_BASE_ADDR 4 | LOADER_STACK_TOP equ LOADER_BASE_ADDR 5 | 6 | jmp loader_start 7 | 8 | ; 这里其实就是GDT的起始地址,第一个描述符为空 9 | GDT_BASE: dd 0x00000000 10 | dd 0x00000000 11 | 12 | ; 代码段描述符,一个dd为4字节,段描述符为8字节,上面为低4字节 13 | CODE_DESC: dd 0x0000FFFF 14 | dd DESC_CODE_HIGH4 15 | 16 | ; 栈段描述符,和数据段共用 17 | DATA_STACK_DESC: dd 0x0000FFFF 18 | dd DESC_DATA_HIGH4 19 | 20 | ; 显卡段,非平坦 21 | VIDEO_DESC: dd 0x80000007 22 | dd DESC_VIDEO_HIGH4 23 | 24 | GDT_SIZE equ $ - GDT_BASE 25 | GDT_LIMIT equ GDT_SIZE - 1 26 | times 120 dd 0 27 | SELECTOR_CODE equ (0x0001 << 3) + TI_GDT + RPL0 28 | SELECTOR_DATA equ (0x0002 << 3) + TI_GDT + RPL0 29 | SELECTOR_VIDEO equ (0x0003 << 3) + TI_GDT + RPL0 30 | 31 | gdt_ptr dw GDT_LIMIT 32 | dd GDT_BASE 33 | 34 | loadermsg db '2 loader in real.' 35 | 36 | loader_start: 37 | 38 | ; 调用10h号中断显示字符串 39 | mov sp, LOADER_BASE_ADDR 40 | mov bp, loadermsg 41 | ; 字符串长度 42 | mov cx, 17 43 | ; 子功能号以及显示方式 44 | mov ax, 0x1301 45 | ; 页号:0, 蓝底粉红字 46 | mov bx, 0x001f 47 | mov dx, 0x1800 48 | int 0x10 49 | 50 | ; 打开A20地址线 51 | in al, 0x92 52 | or al, 00000010B 53 | out 0x92, al 54 | 55 | ; 加载gdt 56 | lgdt [gdt_ptr] 57 | 58 | ; cr0第0位置1 59 | mov eax, cr0 60 | or eax, 0x00000001 61 | mov cr0, eax 62 | 63 | ; 刷新流水线 64 | jmp dword SELECTOR_CODE:p_mode_start 65 | 66 | [bits 32] 67 | p_mode_start: 68 | mov ax, SELECTOR_DATA 69 | mov ds, ax 70 | 71 | mov es, ax 72 | mov ss, ax 73 | 74 | mov esp, LOADER_STACK_TOP 75 | mov ax, SELECTOR_VIDEO 76 | mov gs, ax 77 | 78 | mov byte [gs:160], 'P' 79 | ; 与书中不同,这里使用蓝底白字 80 | mov byte [gs:161], 0x1f 81 | 82 | jmp $ -------------------------------------------------------------------------------- /chapter4/mbr.asm: -------------------------------------------------------------------------------- 1 | ; 主引导程序 2 | ;----------------------------------------------- 3 | %include "boot.inc" 4 | SECTION MBR vstart=0x7c00 5 | 6 | mov ax, cs 7 | mov ds, ax 8 | mov es, ax 9 | mov ss, ax 10 | mov fs, ax 11 | mov sp, 0x7c00 12 | mov ax, 0xb800 13 | mov gs, ax 14 | 15 | ; 清屏 16 | ;--------------------------------------------------- 17 | mov ax, 0600h 18 | mov bx, 0700h 19 | mov cx, 0 20 | mov dx, 184fh 21 | int 10h 22 | 23 | ; 显示"MBR" 24 | mov byte [gs:0x00], '1' 25 | mov byte [gs:0x01], 0xA4 26 | 27 | mov byte [gs:0x02], ' ' 28 | mov byte [gs:0x03], 0xA4 29 | 30 | mov byte [gs:0x04], 'M' 31 | mov byte [gs:0x05], 0xA4 32 | 33 | mov byte [gs:0x06], 'B' 34 | mov byte [gs:0x07], 0xA4 35 | 36 | mov byte [gs:0x08], 'A' 37 | mov byte [gs:0x09], 0xA4 38 | 39 | mov eax, LOADER_START_SECTOR 40 | mov bx, LOADER_BASE_ADDR 41 | 42 | ; 读取4个扇区 43 | mov cx, 4 44 | call rd_disk_m_16 45 | 46 | jmp LOADER_BASE_ADDR 47 | 48 | ;----------------------------------------------------------- 49 | ; 读取磁盘的n个扇区,用于加载loader 50 | ; eax保存从硬盘读取到的数据的保存地址,ebx为起始扇区,cx为读取的扇区数 51 | rd_disk_m_16: 52 | ;----------------------------------------------------------- 53 | 54 | mov esi, eax 55 | mov di, cx 56 | 57 | mov dx, 0x1f2 58 | mov al, cl 59 | out dx, al 60 | 61 | mov eax, esi 62 | 63 | mov dx, 0x1f3 64 | out dx, al 65 | 66 | mov cl, 8 67 | shr eax, cl 68 | mov dx, 0x1f4 69 | out dx, al 70 | 71 | shr eax, cl 72 | mov dx, 0x1f5 73 | out dx, al 74 | 75 | shr eax, cl 76 | and al, 0x0f 77 | or al, 0xe0 78 | mov dx, 0x1f6 79 | out dx, al 80 | 81 | mov dx, 0x1f7 82 | mov al, 0x20 83 | out dx, al 84 | 85 | .not_ready: 86 | nop 87 | in al, dx 88 | and al, 0x88 89 | cmp al, 0x08 90 | jnz .not_ready 91 | 92 | mov ax, di 93 | mov dx, 256 94 | mul dx 95 | mov cx, ax 96 | mov dx, 0x1f0 97 | 98 | .go_on_read: 99 | in ax, dx 100 | mov [bx], ax 101 | add bx, 2 102 | loop .go_on_read 103 | ret 104 | 105 | times 510-($-$$) db 0 106 | db 0x55, 0xaa 107 | -------------------------------------------------------------------------------- /chapter5/detect-memory/bochsrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 对应真实机器的bios 7 | romimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/BIOS-bochs-latest 8 | # 对应真实机器的VGA bios 9 | vgaromimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/VGABIOS-lgpl-latest 10 | 11 | # 启动方式 12 | boot: disk 13 | 14 | # 关闭鼠标 15 | mouse: enabled=0 16 | 17 | # 硬盘设置 18 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 19 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 20 | -------------------------------------------------------------------------------- /chapter5/detect-memory/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Creating disk.img..." 4 | bximage -mode=create -hd=10M -q disk.img 5 | 6 | echo "Compiling..." 7 | nasm -I include/ -o mbr.bin mbr.asm 8 | nasm -I include/ -o loader.bin loader.asm 9 | 10 | echo "Writing mbr and loader to disk..." 11 | dd if=mbr.bin of=disk.img bs=512 count=1 conv=notrunc 12 | dd if=loader.bin of=disk.img bs=512 count=4 seek=2 conv=notrunc 13 | 14 | echo "Now start bochs and have fun!" 15 | bochs -f bochsrc -------------------------------------------------------------------------------- /chapter5/detect-memory/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f disk.img *.bin 4 | -------------------------------------------------------------------------------- /chapter5/detect-memory/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | 5 | ; gdt描述符属性 6 | ; 段描述符高23位,表示段界限的粒度为4KB 7 | DESC_G_4K equ 100000000000000000000000b 8 | 9 | ; D/B为,1表示运行在32位模式下 10 | DESC_D_32 equ 10000000000000000000000b 11 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 12 | DESC_L equ 0000000000000000000000b 13 | ; 没有明确的用途,取值随意 14 | DESC_AVL equ 000000000000000000000b 15 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 16 | DESC_LIMIT_CODE2 equ 11110000000000000000b 17 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 18 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 19 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 20 | DESC_P equ 1000000000000000b 21 | DESC_DPL_0 equ 000000000000000b 22 | DESC_DPL_1 equ 010000000000000b 23 | DESC_DPL_2 equ 100000000000000b 24 | DESC_DPL_3 equ 110000000000000b 25 | DESC_S_CODE equ 1000000000000b 26 | DESC_S_DATA equ DESC_S_CODE 27 | DESC_S_sys equ 0000000000000b 28 | DESC_TYPE_CODE equ 100000000000b 29 | DESC_TYPE_DATA equ 001000000000b 30 | 31 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 32 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 33 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 34 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 35 | 36 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 39 | 40 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | ; 选择字属性 45 | RPL0 equ 00b 46 | RPL1 equ 01b 47 | RPL2 equ 10b 48 | RPL3 equ 11b 49 | TI_GDT equ 000b 50 | TI_LDT equ 100b -------------------------------------------------------------------------------- /chapter5/detect-memory/loader.asm: -------------------------------------------------------------------------------- 1 | %include "boot.inc" 2 | 3 | section loader vstart=LOADER_BASE_ADDR 4 | LOADER_STACK_TOP equ LOADER_BASE_ADDR 5 | 6 | ; 这里其实就是GDT的起始地址,第一个描述符为空 7 | GDT_BASE: dd 0x00000000 8 | dd 0x00000000 9 | 10 | ; 代码段描述符,一个dd为4字节,段描述符为8字节,上面为低4字节 11 | CODE_DESC: dd 0x0000FFFF 12 | dd DESC_CODE_HIGH4 13 | 14 | ; 栈段描述符,和数据段共用 15 | DATA_STACK_DESC: dd 0x0000FFFF 16 | dd DESC_DATA_HIGH4 17 | 18 | ; 显卡段,非平坦 19 | VIDEO_DESC: dd 0x80000007 20 | dd DESC_VIDEO_HIGH4 21 | 22 | GDT_SIZE equ $ - GDT_BASE 23 | GDT_LIMIT equ GDT_SIZE - 1 24 | times 120 dd 0 25 | SELECTOR_CODE equ (0x0001 << 3) + TI_GDT + RPL0 26 | SELECTOR_DATA equ (0x0002 << 3) + TI_GDT + RPL0 27 | SELECTOR_VIDEO equ (0x0003 << 3) + TI_GDT + RPL0 28 | 29 | ; 内存大小,单位字节,此处的内存地址是0xb00 30 | total_memory_bytes dd 0 31 | 32 | gdt_ptr dw GDT_LIMIT 33 | dd GDT_BASE 34 | 35 | ards_buf times 244 db 0 36 | ards_nr dw 0 37 | 38 | loader_start: 39 | 40 | xor ebx, ebx 41 | mov edx, 0x534d4150 42 | mov di, ards_buf 43 | 44 | .e820_mem_get_loop: 45 | mov eax, 0x0000e820 46 | mov ecx, 20 47 | int 0x15 48 | 49 | jc .e820_mem_get_failed 50 | 51 | add di, cx 52 | inc word [ards_nr] 53 | cmp ebx, 0 54 | jnz .e820_mem_get_loop 55 | 56 | mov cx, [ards_nr] 57 | mov ebx, ards_buf 58 | xor edx, edx 59 | 60 | .find_max_mem_area: 61 | mov eax, [ebx] 62 | add eax, [ebx + 8] 63 | add ebx, 20 64 | cmp edx, eax 65 | jge .next_ards 66 | mov edx, eax 67 | 68 | .next_ards: 69 | loop .find_max_mem_area 70 | jmp .mem_get_ok 71 | 72 | .e820_mem_get_failed: 73 | mov byte [gs:0], 'f' 74 | mov byte [gs:2], 'a' 75 | mov byte [gs:4], 'i' 76 | mov byte [gs:6], 'l' 77 | mov byte [gs:8], 'e' 78 | mov byte [gs:10], 'd' 79 | jmp .done 80 | 81 | .mem_get_ok: 82 | mov [total_memory_bytes], edx 83 | 84 | .done: 85 | mov byte [gs:160], 'd' 86 | mov byte [gs:162], 'o' 87 | mov byte [gs:164], 'n' 88 | mov byte [gs:166], 'e' 89 | jmp $ 90 | -------------------------------------------------------------------------------- /chapter5/load-kernel/bochsrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 对应真实机器的bios 7 | romimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/BIOS-bochs-latest 8 | # 对应真实机器的VGA bios 9 | vgaromimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/VGABIOS-lgpl-latest 10 | 11 | # 启动方式 12 | boot: disk 13 | 14 | # 关闭鼠标 15 | mouse: enabled=0 16 | 17 | # 硬盘设置 18 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 19 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 20 | -------------------------------------------------------------------------------- /chapter5/load-kernel/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | shopt -s expand_aliases 4 | 5 | echo "Creating disk.img..." 6 | bximage -mode=create -hd=10M -q disk.img 7 | 8 | echo "Compiling..." 9 | /usr/local/i386elfgcc/bin/i386-elf-gcc -c -o kernel/main.o kernel/main.c 10 | /usr/local/i386elfgcc/bin/i386-elf-ld kernel/main.o -Ttext 0xc0001500 -e main -o kernel/kernel.bin 11 | nasm -I include/ -o mbr.bin mbr.asm 12 | nasm -I include/ -o loader.bin loader.asm 13 | 14 | echo "Writing mbr, loader and kernel to disk..." 15 | dd if=mbr.bin of=disk.img bs=512 count=1 conv=notrunc 16 | dd if=loader.bin of=disk.img bs=512 count=4 seek=2 conv=notrunc 17 | dd if=kernel/kernel.bin of=disk.img bs=512 count=200 seek=9 conv=notrunc 18 | 19 | echo "Now start bochs and have fun!" 20 | bochs -f bochsrc 21 | -------------------------------------------------------------------------------- /chapter5/load-kernel/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f disk.img *.bin kernel/*.bin kernel/*.o 4 | -------------------------------------------------------------------------------- /chapter5/load-kernel/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_START_SECTOR equ 0x9 6 | KERNEL_BIN_BASE_ADDR equ 0x70000 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ; gdt描述符属性 10 | ; 段描述符高23位,表示段界限的粒度为4KB 11 | DESC_G_4K equ 100000000000000000000000b 12 | 13 | ; D/B为,1表示运行在32位模式下 14 | DESC_D_32 equ 10000000000000000000000b 15 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 16 | DESC_L equ 0000000000000000000000b 17 | ; 没有明确的用途,取值随意 18 | DESC_AVL equ 000000000000000000000b 19 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 20 | DESC_LIMIT_CODE2 equ 11110000000000000000b 21 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 22 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 23 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 24 | DESC_P equ 1000000000000000b 25 | DESC_DPL_0 equ 000000000000000b 26 | DESC_DPL_1 equ 010000000000000b 27 | DESC_DPL_2 equ 100000000000000b 28 | DESC_DPL_3 equ 110000000000000b 29 | DESC_S_CODE equ 1000000000000b 30 | DESC_S_DATA equ DESC_S_CODE 31 | DESC_S_sys equ 0000000000000b 32 | DESC_TYPE_CODE equ 100000000000b 33 | DESC_TYPE_DATA equ 001000000000b 34 | 35 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 36 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 39 | 40 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 45 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 46 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 47 | 48 | ; 选择字属性 49 | RPL0 equ 00b 50 | RPL1 equ 01b 51 | RPL2 equ 10b 52 | RPL3 equ 11b 53 | TI_GDT equ 000b 54 | TI_LDT equ 100b 55 | 56 | ; 页表相关属性 57 | PG_P equ 1b 58 | PG_RW_R equ 00b 59 | PG_RW_W equ 10b 60 | PG_US_S equ 000b 61 | PG_US_U equ 100b 62 | 63 | PT_NULL equ 0 -------------------------------------------------------------------------------- /chapter5/load-kernel/kernel/main.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | while (1); 3 | return 0; 4 | } -------------------------------------------------------------------------------- /chapter5/page-memory/bochsrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 对应真实机器的bios 7 | romimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/BIOS-bochs-latest 8 | # 对应真实机器的VGA bios 9 | vgaromimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/VGABIOS-lgpl-latest 10 | 11 | # 启动方式 12 | boot: disk 13 | 14 | # 关闭鼠标 15 | mouse: enabled=0 16 | 17 | # 硬盘设置 18 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 19 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 20 | -------------------------------------------------------------------------------- /chapter5/page-memory/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Creating disk.img..." 4 | bximage -mode=create -hd=10M -q disk.img 5 | 6 | echo "Compiling..." 7 | nasm -I include/ -o mbr.bin mbr.asm 8 | nasm -I include/ -o loader.bin loader.asm 9 | 10 | echo "Writing mbr and loader to disk..." 11 | dd if=mbr.bin of=disk.img bs=512 count=1 conv=notrunc 12 | dd if=loader.bin of=disk.img bs=512 count=4 seek=2 conv=notrunc 13 | 14 | echo "Now start bochs and have fun!" 15 | bochs -f bochsrc -------------------------------------------------------------------------------- /chapter5/page-memory/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f disk.img *.bin 4 | -------------------------------------------------------------------------------- /chapter5/page-memory/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | 6 | ; gdt描述符属性 7 | ; 段描述符高23位,表示段界限的粒度为4KB 8 | DESC_G_4K equ 100000000000000000000000b 9 | 10 | ; D/B为,1表示运行在32位模式下 11 | DESC_D_32 equ 10000000000000000000000b 12 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 13 | DESC_L equ 0000000000000000000000b 14 | ; 没有明确的用途,取值随意 15 | DESC_AVL equ 000000000000000000000b 16 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 17 | DESC_LIMIT_CODE2 equ 11110000000000000000b 18 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 19 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 20 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 21 | DESC_P equ 1000000000000000b 22 | DESC_DPL_0 equ 000000000000000b 23 | DESC_DPL_1 equ 010000000000000b 24 | DESC_DPL_2 equ 100000000000000b 25 | DESC_DPL_3 equ 110000000000000b 26 | DESC_S_CODE equ 1000000000000b 27 | DESC_S_DATA equ DESC_S_CODE 28 | DESC_S_sys equ 0000000000000b 29 | DESC_TYPE_CODE equ 100000000000b 30 | DESC_TYPE_DATA equ 001000000000b 31 | 32 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 33 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 34 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 35 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 36 | 37 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 38 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 39 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 40 | 41 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 42 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 43 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 44 | 45 | ; 选择字属性 46 | RPL0 equ 00b 47 | RPL1 equ 01b 48 | RPL2 equ 10b 49 | RPL3 equ 11b 50 | TI_GDT equ 000b 51 | TI_LDT equ 100b 52 | 53 | ; 页表相关属性 54 | PG_P equ 1b 55 | PG_RW_R equ 00b 56 | PG_RW_W equ 10b 57 | PG_US_S equ 000b 58 | PG_US_U equ 100b -------------------------------------------------------------------------------- /chapter6/bochsrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 对应真实机器的bios 7 | romimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/BIOS-bochs-latest 8 | # 对应真实机器的VGA bios 9 | vgaromimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/VGABIOS-lgpl-latest 10 | 11 | # 启动方式 12 | boot: disk 13 | 14 | # 关闭鼠标 15 | mouse: enabled=0 16 | 17 | # 硬盘设置 18 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 19 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 20 | -------------------------------------------------------------------------------- /chapter6/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | shopt -s expand_aliases 4 | 5 | echo "Creating disk.img..." 6 | bximage -mode=create -hd=10M -q disk.img 7 | 8 | echo "Compiling..." 9 | nasm -I include/ -o mbr.bin mbr.asm 10 | nasm -I include/ -o loader.bin loader.asm 11 | nasm -f elf -o lib/kernel/print.o lib/kernel/print.asm 12 | /usr/local/i386elfgcc/bin/i386-elf-gcc -I ./lib/ -c -o kernel/main.o kernel/main.c 13 | /usr/local/i386elfgcc/bin/i386-elf-ld -Ttext 0xc0001500 -e main -o kernel/kernel.bin kernel/main.o lib/kernel/print.o 14 | 15 | echo "Writing mbr, loader and kernel to disk..." 16 | dd if=mbr.bin of=disk.img bs=512 count=1 conv=notrunc 17 | dd if=loader.bin of=disk.img bs=512 count=4 seek=2 conv=notrunc 18 | dd if=kernel/kernel.bin of=disk.img bs=512 count=200 seek=9 conv=notrunc 19 | 20 | echo "Now start bochs and have fun!" 21 | bochs -f bochsrc 22 | -------------------------------------------------------------------------------- /chapter6/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f disk.img *.bin kernel/*.bin kernel/*.o lib/kernel/*.o 4 | -------------------------------------------------------------------------------- /chapter6/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_START_SECTOR equ 0x9 6 | KERNEL_BIN_BASE_ADDR equ 0x70000 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ; gdt描述符属性 10 | ; 段描述符高23位,表示段界限的粒度为4KB 11 | DESC_G_4K equ 100000000000000000000000b 12 | 13 | ; D/B为,1表示运行在32位模式下 14 | DESC_D_32 equ 10000000000000000000000b 15 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 16 | DESC_L equ 0000000000000000000000b 17 | ; 没有明确的用途,取值随意 18 | DESC_AVL equ 000000000000000000000b 19 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 20 | DESC_LIMIT_CODE2 equ 11110000000000000000b 21 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 22 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 23 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 24 | DESC_P equ 1000000000000000b 25 | DESC_DPL_0 equ 000000000000000b 26 | DESC_DPL_1 equ 010000000000000b 27 | DESC_DPL_2 equ 100000000000000b 28 | DESC_DPL_3 equ 110000000000000b 29 | DESC_S_CODE equ 1000000000000b 30 | DESC_S_DATA equ DESC_S_CODE 31 | DESC_S_sys equ 0000000000000b 32 | DESC_TYPE_CODE equ 100000000000b 33 | DESC_TYPE_DATA equ 001000000000b 34 | 35 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 36 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 39 | 40 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 45 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 46 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 47 | 48 | ; 选择字属性 49 | RPL0 equ 00b 50 | RPL1 equ 01b 51 | RPL2 equ 10b 52 | RPL3 equ 11b 53 | TI_GDT equ 000b 54 | TI_LDT equ 100b 55 | 56 | ; 页表相关属性 57 | PG_P equ 1b 58 | PG_RW_R equ 00b 59 | PG_RW_W equ 10b 60 | PG_US_S equ 000b 61 | PG_US_U equ 100b 62 | 63 | PT_NULL equ 0 -------------------------------------------------------------------------------- /chapter6/kernel/main.c: -------------------------------------------------------------------------------- 1 | # include "kernel/print.h" 2 | 3 | int main(void) { 4 | put_char('k'); 5 | put_char('e'); 6 | put_char('r'); 7 | put_char('n'); 8 | put_char('e'); 9 | put_char('l'); 10 | put_char('\n'); 11 | put_char('1'); 12 | put_char('2'); 13 | put_char('\b'); 14 | put_char('3'); 15 | put_char('\n'); 16 | put_str("I am kernel!\n"); 17 | 18 | put_int(7); 19 | put_char('\n'); 20 | put_int(0x7c00); 21 | 22 | while (1); 23 | return 0; 24 | } -------------------------------------------------------------------------------- /chapter6/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 为print.asm提供方便引用的头文件定义. 3 | */ 4 | #ifndef _LIB_KERNEL_PRINT_H 5 | #define _LIB_KERNEL_PRINT_H 6 | 7 | # include "stdint.h" 8 | 9 | void put_char(uint8_t char_asci); 10 | 11 | /** 12 | * 字符串打印,必须以\0结尾. 13 | */ 14 | void put_str(char* message); 15 | 16 | /** 17 | * 以16进制的形式打印数字. 18 | */ 19 | void put_int(uint32_t num); 20 | 21 | #endif -------------------------------------------------------------------------------- /chapter6/lib/stdint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 仿照/usr/include/stdint.h定义我们自己的数据类型. 3 | */ 4 | #ifndef _LIB_STDINT_H 5 | #define _LIB_STDINT_H 6 | 7 | typedef signed char int8_t; 8 | typedef signed short int int16_t; 9 | typedef signed int int32_t; 10 | typedef signed long long int int64_t; 11 | 12 | typedef unsigned char uint8_t; 13 | typedef unsigned short int uint16_t; 14 | typedef unsigned int uint32_t; 15 | typedef unsigned long long int uint64_t; 16 | 17 | #endif -------------------------------------------------------------------------------- /chapter7/improve/bochsrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 对应真实机器的bios 7 | romimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/BIOS-bochs-latest 8 | # 对应真实机器的VGA bios 9 | vgaromimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/VGABIOS-lgpl-latest 10 | 11 | # 启动方式 12 | boot: disk 13 | 14 | # 关闭鼠标 15 | mouse: enabled=0 16 | 17 | # 硬盘设置 18 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 19 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 20 | -------------------------------------------------------------------------------- /chapter7/improve/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir build 4 | 5 | echo "Creating disk.img..." 6 | bximage -mode=create -hd=10M -q disk.img 7 | 8 | echo "Compiling..." 9 | nasm -I include/ -o build/mbr.bin mbr.asm 10 | nasm -I include/ -o build/loader.bin loader.asm 11 | /usr/local/i386elfgcc/bin/i386-elf-gcc -I lib/ -I kernel/ -c -fno-builtin -o build/main.o kernel/main.c 12 | nasm -f elf -o build/print.o lib/kernel/print.asm 13 | nasm -f elf -o build/kernel.o kernel/kernel.asm 14 | /usr/local/i386elfgcc/bin/i386-elf-gcc -I lib/ -I kernel/ -c -fno-builtin -o build/interrupt.o kernel/interrupt.c 15 | /usr/local/i386elfgcc/bin/i386-elf-gcc -I lib/ -I kernel/ -c -fno-builtin -o build/init.o kernel/init.c 16 | /usr/local/i386elfgcc/bin/i386-elf-ld -Ttext 0xc0001500 -e main -o build/kernel.bin build/main.o build/init.o build/interrupt.o build/print.o build/kernel.o 17 | 18 | echo "Writing mbr, loader and kernel to disk..." 19 | dd if=build/mbr.bin of=disk.img bs=512 count=1 conv=notrunc 20 | dd if=build/loader.bin of=disk.img bs=512 count=4 seek=2 conv=notrunc 21 | dd if=build/kernel.bin of=disk.img bs=512 count=200 seek=9 conv=notrunc 22 | 23 | echo "Now start bochs and have fun!" 24 | bochs -f bochsrc 25 | -------------------------------------------------------------------------------- /chapter7/improve/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf disk.img build/ 4 | -------------------------------------------------------------------------------- /chapter7/improve/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_START_SECTOR equ 0x9 6 | KERNEL_BIN_BASE_ADDR equ 0x70000 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ; gdt描述符属性 10 | ; 段描述符高23位,表示段界限的粒度为4KB 11 | DESC_G_4K equ 100000000000000000000000b 12 | 13 | ; D/B为,1表示运行在32位模式下 14 | DESC_D_32 equ 10000000000000000000000b 15 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 16 | DESC_L equ 0000000000000000000000b 17 | ; 没有明确的用途,取值随意 18 | DESC_AVL equ 000000000000000000000b 19 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 20 | DESC_LIMIT_CODE2 equ 11110000000000000000b 21 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 22 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 23 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 24 | DESC_P equ 1000000000000000b 25 | DESC_DPL_0 equ 000000000000000b 26 | DESC_DPL_1 equ 010000000000000b 27 | DESC_DPL_2 equ 100000000000000b 28 | DESC_DPL_3 equ 110000000000000b 29 | DESC_S_CODE equ 1000000000000b 30 | DESC_S_DATA equ DESC_S_CODE 31 | DESC_S_sys equ 0000000000000b 32 | DESC_TYPE_CODE equ 100000000000b 33 | DESC_TYPE_DATA equ 001000000000b 34 | 35 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 36 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 39 | 40 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 45 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 46 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 47 | 48 | ; 选择字属性 49 | RPL0 equ 00b 50 | RPL1 equ 01b 51 | RPL2 equ 10b 52 | RPL3 equ 11b 53 | TI_GDT equ 000b 54 | TI_LDT equ 100b 55 | 56 | ; 页表相关属性 57 | PG_P equ 1b 58 | PG_RW_R equ 00b 59 | PG_RW_W equ 10b 60 | PG_US_S equ 000b 61 | PG_US_U equ 100b 62 | 63 | PT_NULL equ 0 -------------------------------------------------------------------------------- /chapter7/improve/kernel/global.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_GLOBAL_H 2 | #define _KERNEL_GLOBAL_H 3 | 4 | # include "stdint.h" 5 | 6 | # define RPL0 0 7 | # define RPL1 1 8 | # define RPL2 2 9 | # define RPL3 3 10 | 11 | # define TI_GDT 0 12 | # define TI_LDT 1 13 | 14 | # define SELECTOR_K_CODE ((1 << 3) + (TI_GDT << 2) + RPL0) 15 | # define SELECTOR_K_DATA ((2 << 3) + (TI_GDT << 2) + RPL0) 16 | # define SELECTOR_K_STACK SELECTOR_K_DATA 17 | # define SELECTOR_K_GS ((3 << 3) + (TI_GDT << 2) + RPL0) 18 | 19 | /* IDT描述符属性 */ 20 | # define IDT_DESC_P 1 21 | # define IDT_DESC_DPL0 0 22 | # define IDT_DESC_DPL3 3 23 | # define IDT_DESC_32_TYPE 0xE 24 | # define IDT_DESC_16_TYPE 0x6 25 | 26 | # define IDT_DESC_ATTR_DPL0 \ 27 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL0 << 5) + IDT_DESC_32_TYPE) 28 | 29 | # define IDT_DESC_ATTR_DPL3 \ 30 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL3 << 5) + IDT_DESC_32_TYPE) 31 | 32 | #endif -------------------------------------------------------------------------------- /chapter7/improve/kernel/init.c: -------------------------------------------------------------------------------- 1 | # include "init.h" 2 | # include "kernel/print.h" 3 | 4 | void init_all() { 5 | put_str("init_all.\n"); 6 | idt_init(); 7 | } -------------------------------------------------------------------------------- /chapter7/improve/kernel/init.h: -------------------------------------------------------------------------------- 1 | void init_all(void); -------------------------------------------------------------------------------- /chapter7/improve/kernel/interrupt.h: -------------------------------------------------------------------------------- 1 | typedef void* intr_handler; -------------------------------------------------------------------------------- /chapter7/improve/kernel/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_IO_H 2 | # define _LIB_IO_H 3 | 4 | # include "stdint.h" 5 | 6 | /** 7 | * 向指定的端口写入一个字节的数据. 8 | */ 9 | static inline void outb(uint16_t port, uint8_t data) { 10 | asm volatile ("outb %b0, %w1" : : "a" (data), "Nd" (port)); 11 | } 12 | 13 | /** 14 | * 将addr起始处的word_cnt个字节写入端口port. 15 | */ 16 | static inline void outsw(uint16_t port, const void* addr, uint32_t word_cnt) { 17 | asm volatile ("cld; rep outsw" : "+S" (addr), "+c" (word_cnt) : "d" (port)); 18 | } 19 | 20 | /** 21 | * 将从端口port读入的一个字节返回. 22 | */ 23 | static inline uint8_t inb(uint16_t port) { 24 | uint8_t data; 25 | asm volatile ("inb %w1, %b0" : "=a" (data) : "Nd" (port)); 26 | return data; 27 | } 28 | 29 | /** 30 | * 将从port读取的word_cnt字节写入addr. 31 | */ 32 | static inline void insw(uint16_t port, void* addr, uint32_t word_cnt) { 33 | asm volatile ("cld; rep insw" : "+D" (addr), "+c" (word_cnt) : "d" (port) : "memory"); 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /chapter7/improve/kernel/kernel.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ; 对于CPU会自动压入错误码的中断类型,无需额外的操作 4 | %define ERROR_CODE nop 5 | ; 如果CPU没有压入错误码,为了保持处理逻辑的一致性,我们需要手动压入一个0 6 | %define ZERO push 0 7 | 8 | extern put_str 9 | ; 中断处理函数数组 10 | extern idt_table 11 | 12 | section .data 13 | intr_str db "interrupt occur!", 0xa, 0 14 | global intr_entry_table 15 | intr_entry_table: 16 | 17 | ; 中断处理程序宏定义 18 | %macro VECTOR 2 19 | section .text 20 | intr%1entry: 21 | 22 | %2 23 | ; 保存上下文 24 | push ds 25 | push es 26 | push fs 27 | push gs 28 | pushad 29 | 30 | mov al, 0x20 31 | out 0xa0, al 32 | out 0x20, al 33 | 34 | push %1 35 | 36 | ; 调用C的中断处理函数 37 | call [idt_table + 4 * %1] 38 | jmp intr_exit 39 | 40 | section .data 41 | dd intr%1entry 42 | 43 | %endmacro 44 | 45 | section .text 46 | global intr_exit 47 | intr_exit: 48 | add esp, 4 49 | popad 50 | pop gs 51 | pop fs 52 | pop es 53 | pop ds 54 | add esp, 4 55 | iretd 56 | 57 | VECTOR 0x00, ZERO 58 | VECTOR 0x01, ZERO 59 | VECTOR 0x02, ZERO 60 | VECTOR 0x03, ZERO 61 | VECTOR 0x04, ZERO 62 | VECTOR 0x05, ZERO 63 | VECTOR 0x06, ZERO 64 | VECTOR 0x07, ZERO 65 | VECTOR 0x08, ZERO 66 | VECTOR 0x09, ZERO 67 | VECTOR 0x0a, ZERO 68 | VECTOR 0x0b, ZERO 69 | VECTOR 0x0c, ZERO 70 | VECTOR 0x0d, ZERO 71 | VECTOR 0x0e, ZERO 72 | VECTOR 0x0f, ZERO 73 | VECTOR 0x10, ZERO 74 | VECTOR 0x11, ZERO 75 | VECTOR 0x12, ZERO 76 | VECTOR 0x13, ZERO 77 | VECTOR 0x14, ZERO 78 | VECTOR 0x15, ZERO 79 | VECTOR 0x16, ZERO 80 | VECTOR 0x17, ZERO 81 | VECTOR 0x18, ZERO 82 | VECTOR 0x19, ZERO 83 | VECTOR 0x1a, ZERO 84 | VECTOR 0x1b, ZERO 85 | VECTOR 0x1c, ZERO 86 | VECTOR 0x1d, ZERO 87 | VECTOR 0x1e, ERROR_CODE 88 | VECTOR 0x1f, ZERO 89 | VECTOR 0x20, ZERO -------------------------------------------------------------------------------- /chapter7/improve/kernel/main.c: -------------------------------------------------------------------------------- 1 | # include "kernel/print.h" 2 | # include "init.h" 3 | 4 | void main(void) { 5 | put_str("I am kernel.\n"); 6 | init_all(); 7 | put_str("Init finished.\n"); 8 | asm volatile ("sti"); 9 | put_str("Turn on the interrupt.\n"); 10 | while (1); 11 | } -------------------------------------------------------------------------------- /chapter7/improve/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 为print.asm提供方便引用的头文件定义. 3 | */ 4 | #ifndef _LIB_KERNEL_PRINT_H 5 | #define _LIB_KERNEL_PRINT_H 6 | 7 | # include "stdint.h" 8 | 9 | void put_char(uint8_t char_asci); 10 | 11 | /** 12 | * 字符串打印,必须以\0结尾. 13 | */ 14 | void put_str(char* message); 15 | 16 | /** 17 | * 以16进制的形式打印数字. 18 | */ 19 | void put_int(uint32_t num); 20 | 21 | #endif -------------------------------------------------------------------------------- /chapter7/improve/lib/stdint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 仿照/usr/include/stdint.h定义我们自己的数据类型. 3 | */ 4 | #ifndef _LIB_STDINT_H 5 | #define _LIB_STDINT_H 6 | 7 | typedef signed char int8_t; 8 | typedef signed short int int16_t; 9 | typedef signed int int32_t; 10 | typedef signed long long int int64_t; 11 | 12 | typedef unsigned char uint8_t; 13 | typedef unsigned short int uint16_t; 14 | typedef unsigned int uint32_t; 15 | typedef unsigned long long int uint64_t; 16 | 17 | #endif -------------------------------------------------------------------------------- /chapter7/timer/bochsrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 对应真实机器的bios 7 | romimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/BIOS-bochs-latest 8 | # 对应真实机器的VGA bios 9 | vgaromimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/VGABIOS-lgpl-latest 10 | 11 | # 启动方式 12 | boot: disk 13 | 14 | # 关闭鼠标 15 | mouse: enabled=0 16 | 17 | # 硬盘设置 18 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 19 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 20 | -------------------------------------------------------------------------------- /chapter7/timer/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir build 4 | 5 | echo "Creating disk.img..." 6 | bximage -mode=create -hd=10M -q disk.img 7 | 8 | echo "Compiling..." 9 | 10 | nasm -I include/ -o build/mbr.bin mbr.asm 11 | nasm -I include/ -o build/loader.bin loader.asm 12 | /usr/local/i386elfgcc/bin/i386-elf-gcc -I lib/ -I kernel/ -c -o build/timer.o device/timer.c 13 | /usr/local/i386elfgcc/bin/i386-elf-gcc -I lib/ -I kernel/ -c -fno-builtin -o build/main.o kernel/main.c 14 | nasm -f elf -o build/print.o lib/kernel/print.asm 15 | nasm -f elf -o build/kernel.o kernel/kernel.asm 16 | /usr/local/i386elfgcc/bin/i386-elf-gcc -I lib/ -I kernel/ -c -fno-builtin -o build/interrupt.o kernel/interrupt.c 17 | /usr/local/i386elfgcc/bin/i386-elf-gcc -I lib/ -I device/ -I kernel/ -c -fno-builtin -o build/init.o kernel/init.c 18 | /usr/local/i386elfgcc/bin/i386-elf-ld -Ttext 0xc0001500 -e main -o build/kernel.bin build/main.o build/init.o build/interrupt.o build/print.o build/kernel.o build/timer.o 19 | 20 | echo "Writing mbr, loader and kernel to disk..." 21 | dd if=build/mbr.bin of=disk.img bs=512 count=1 conv=notrunc 22 | dd if=build/loader.bin of=disk.img bs=512 count=4 seek=2 conv=notrunc 23 | dd if=build/kernel.bin of=disk.img bs=512 count=200 seek=9 conv=notrunc 24 | 25 | echo "Now start bochs and have fun!" 26 | bochs -f bochsrc 27 | -------------------------------------------------------------------------------- /chapter7/timer/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf disk.img build/ 4 | -------------------------------------------------------------------------------- /chapter7/timer/device/timer.c: -------------------------------------------------------------------------------- 1 | # include "io.h" 2 | # include "kernel/print.h" 3 | 4 | # define IRQ0_FREQUENCY 1000 5 | # define INPUT_FREQUENCY 1193180 6 | # define COUNTER0_VALUE INPUT_FREQUENCY / IRQ0_FREQUENCY 7 | # define COUNTER0_PORT 0x40 8 | # define COUNTER_MODE 2 9 | # define COUNTER0_NO 0 10 | # define READ_WRITE_LATCH 3 11 | # define PIT_CONTROL_PORT 0x43 12 | 13 | 14 | static void frequency_set(uint8_t counter_port, 15 | uint8_t counter_no, 16 | uint8_t rwl, 17 | uint8_t counter_mode, 18 | uint16_t counter_value) { 19 | outb(PIT_CONTROL_PORT, (uint8_t) (counter_no << 6 | rwl << 4 | counter_mode << 1)); 20 | outb(counter_port, (uint8_t) counter_value); 21 | outb(counter_port, (uint8_t) counter_value >> 8); 22 | } 23 | 24 | /** 25 | * 初始化PIT 8253. 26 | */ 27 | void timer_init() { 28 | put_str("timer_init start.\n"); 29 | frequency_set(COUNTER0_PORT, COUNTER0_NO, READ_WRITE_LATCH, COUNTER_MODE, COUNTER0_VALUE); 30 | put_str("timer_init done.\n"); 31 | } -------------------------------------------------------------------------------- /chapter7/timer/device/timer.h: -------------------------------------------------------------------------------- 1 | void timer_init(); -------------------------------------------------------------------------------- /chapter7/timer/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_START_SECTOR equ 0x9 6 | KERNEL_BIN_BASE_ADDR equ 0x70000 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ; gdt描述符属性 10 | ; 段描述符高23位,表示段界限的粒度为4KB 11 | DESC_G_4K equ 100000000000000000000000b 12 | 13 | ; D/B为,1表示运行在32位模式下 14 | DESC_D_32 equ 10000000000000000000000b 15 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 16 | DESC_L equ 0000000000000000000000b 17 | ; 没有明确的用途,取值随意 18 | DESC_AVL equ 000000000000000000000b 19 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 20 | DESC_LIMIT_CODE2 equ 11110000000000000000b 21 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 22 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 23 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 24 | DESC_P equ 1000000000000000b 25 | DESC_DPL_0 equ 000000000000000b 26 | DESC_DPL_1 equ 010000000000000b 27 | DESC_DPL_2 equ 100000000000000b 28 | DESC_DPL_3 equ 110000000000000b 29 | DESC_S_CODE equ 1000000000000b 30 | DESC_S_DATA equ DESC_S_CODE 31 | DESC_S_sys equ 0000000000000b 32 | DESC_TYPE_CODE equ 100000000000b 33 | DESC_TYPE_DATA equ 001000000000b 34 | 35 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 36 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 39 | 40 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 45 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 46 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 47 | 48 | ; 选择字属性 49 | RPL0 equ 00b 50 | RPL1 equ 01b 51 | RPL2 equ 10b 52 | RPL3 equ 11b 53 | TI_GDT equ 000b 54 | TI_LDT equ 100b 55 | 56 | ; 页表相关属性 57 | PG_P equ 1b 58 | PG_RW_R equ 00b 59 | PG_RW_W equ 10b 60 | PG_US_S equ 000b 61 | PG_US_U equ 100b 62 | 63 | PT_NULL equ 0 -------------------------------------------------------------------------------- /chapter7/timer/kernel/global.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_GLOBAL_H 2 | #define _KERNEL_GLOBAL_H 3 | 4 | # include "stdint.h" 5 | 6 | # define RPL0 0 7 | # define RPL1 1 8 | # define RPL2 2 9 | # define RPL3 3 10 | 11 | # define TI_GDT 0 12 | # define TI_LDT 1 13 | 14 | # define SELECTOR_K_CODE ((1 << 3) + (TI_GDT << 2) + RPL0) 15 | # define SELECTOR_K_DATA ((2 << 3) + (TI_GDT << 2) + RPL0) 16 | # define SELECTOR_K_STACK SELECTOR_K_DATA 17 | # define SELECTOR_K_GS ((3 << 3) + (TI_GDT << 2) + RPL0) 18 | 19 | /* IDT描述符属性 */ 20 | # define IDT_DESC_P 1 21 | # define IDT_DESC_DPL0 0 22 | # define IDT_DESC_DPL3 3 23 | # define IDT_DESC_32_TYPE 0xE 24 | # define IDT_DESC_16_TYPE 0x6 25 | 26 | # define IDT_DESC_ATTR_DPL0 \ 27 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL0 << 5) + IDT_DESC_32_TYPE) 28 | 29 | # define IDT_DESC_ATTR_DPL3 \ 30 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL3 << 5) + IDT_DESC_32_TYPE) 31 | 32 | #endif -------------------------------------------------------------------------------- /chapter7/timer/kernel/init.c: -------------------------------------------------------------------------------- 1 | # include "init.h" 2 | # include "kernel/print.h" 3 | # include "timer.h" 4 | 5 | void init_all() { 6 | put_str("init_all.\n"); 7 | idt_init(); 8 | timer_init(); 9 | } -------------------------------------------------------------------------------- /chapter7/timer/kernel/init.h: -------------------------------------------------------------------------------- 1 | void init_all(void); -------------------------------------------------------------------------------- /chapter7/timer/kernel/interrupt.h: -------------------------------------------------------------------------------- 1 | typedef void* intr_handler; -------------------------------------------------------------------------------- /chapter7/timer/kernel/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_IO_H 2 | # define _LIB_IO_H 3 | 4 | # include "stdint.h" 5 | 6 | /** 7 | * 向指定的端口写入一个字节的数据. 8 | */ 9 | static inline void outb(uint16_t port, uint8_t data) { 10 | asm volatile ("outb %b0, %w1" : : "a" (data), "Nd" (port)); 11 | } 12 | 13 | /** 14 | * 将addr起始处的word_cnt个字节写入端口port. 15 | */ 16 | static inline void outsw(uint16_t port, const void* addr, uint32_t word_cnt) { 17 | asm volatile ("cld; rep outsw" : "+S" (addr), "+c" (word_cnt) : "d" (port)); 18 | } 19 | 20 | /** 21 | * 将从端口port读入的一个字节返回. 22 | */ 23 | static inline uint8_t inb(uint16_t port) { 24 | uint8_t data; 25 | asm volatile ("inb %w1, %b0" : "=a" (data) : "Nd" (port)); 26 | return data; 27 | } 28 | 29 | /** 30 | * 将从port读取的word_cnt字节写入addr. 31 | */ 32 | static inline void insw(uint16_t port, void* addr, uint32_t word_cnt) { 33 | asm volatile ("cld; rep insw" : "+D" (addr), "+c" (word_cnt) : "d" (port) : "memory"); 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /chapter7/timer/kernel/kernel.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ; 对于CPU会自动压入错误码的中断类型,无需额外的操作 4 | %define ERROR_CODE nop 5 | ; 如果CPU没有压入错误码,为了保持处理逻辑的一致性,我们需要手动压入一个0 6 | %define ZERO push 0 7 | 8 | extern put_str 9 | ; 中断处理函数数组 10 | extern idt_table 11 | 12 | section .data 13 | intr_str db "interrupt occur!", 0xa, 0 14 | global intr_entry_table 15 | intr_entry_table: 16 | 17 | ; 中断处理程序宏定义 18 | %macro VECTOR 2 19 | section .text 20 | intr%1entry: 21 | 22 | %2 23 | ; 保存上下文 24 | push ds 25 | push es 26 | push fs 27 | push gs 28 | pushad 29 | 30 | mov al, 0x20 31 | out 0xa0, al 32 | out 0x20, al 33 | 34 | push %1 35 | 36 | ; 调用C的中断处理函数 37 | call [idt_table + 4 * %1] 38 | jmp intr_exit 39 | 40 | section .data 41 | dd intr%1entry 42 | 43 | %endmacro 44 | 45 | section .text 46 | global intr_exit 47 | intr_exit: 48 | add esp, 4 49 | popad 50 | pop gs 51 | pop fs 52 | pop es 53 | pop ds 54 | add esp, 4 55 | iretd 56 | 57 | VECTOR 0x00, ZERO 58 | VECTOR 0x01, ZERO 59 | VECTOR 0x02, ZERO 60 | VECTOR 0x03, ZERO 61 | VECTOR 0x04, ZERO 62 | VECTOR 0x05, ZERO 63 | VECTOR 0x06, ZERO 64 | VECTOR 0x07, ZERO 65 | VECTOR 0x08, ZERO 66 | VECTOR 0x09, ZERO 67 | VECTOR 0x0a, ZERO 68 | VECTOR 0x0b, ZERO 69 | VECTOR 0x0c, ZERO 70 | VECTOR 0x0d, ZERO 71 | VECTOR 0x0e, ZERO 72 | VECTOR 0x0f, ZERO 73 | VECTOR 0x10, ZERO 74 | VECTOR 0x11, ZERO 75 | VECTOR 0x12, ZERO 76 | VECTOR 0x13, ZERO 77 | VECTOR 0x14, ZERO 78 | VECTOR 0x15, ZERO 79 | VECTOR 0x16, ZERO 80 | VECTOR 0x17, ZERO 81 | VECTOR 0x18, ZERO 82 | VECTOR 0x19, ZERO 83 | VECTOR 0x1a, ZERO 84 | VECTOR 0x1b, ZERO 85 | VECTOR 0x1c, ZERO 86 | VECTOR 0x1d, ZERO 87 | VECTOR 0x1e, ERROR_CODE 88 | VECTOR 0x1f, ZERO 89 | VECTOR 0x20, ZERO -------------------------------------------------------------------------------- /chapter7/timer/kernel/main.c: -------------------------------------------------------------------------------- 1 | # include "kernel/print.h" 2 | # include "init.h" 3 | 4 | void main(void) { 5 | put_str("I am kernel.\n"); 6 | init_all(); 7 | put_str("Init finished.\n"); 8 | asm volatile ("sti"); 9 | put_str("Turn on the interrupt.\n"); 10 | while (1); 11 | } -------------------------------------------------------------------------------- /chapter7/timer/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 为print.asm提供方便引用的头文件定义. 3 | */ 4 | #ifndef _LIB_KERNEL_PRINT_H 5 | #define _LIB_KERNEL_PRINT_H 6 | 7 | # include "stdint.h" 8 | 9 | void put_char(uint8_t char_asci); 10 | 11 | /** 12 | * 字符串打印,必须以\0结尾. 13 | */ 14 | void put_str(char* message); 15 | 16 | /** 17 | * 以16进制的形式打印数字. 18 | */ 19 | void put_int(uint32_t num); 20 | 21 | #endif -------------------------------------------------------------------------------- /chapter7/timer/lib/stdint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 仿照/usr/include/stdint.h定义我们自己的数据类型. 3 | */ 4 | #ifndef _LIB_STDINT_H 5 | #define _LIB_STDINT_H 6 | 7 | typedef signed char int8_t; 8 | typedef signed short int int16_t; 9 | typedef signed int int32_t; 10 | typedef signed long long int int64_t; 11 | 12 | typedef unsigned char uint8_t; 13 | typedef unsigned short int uint16_t; 14 | typedef unsigned int uint32_t; 15 | typedef unsigned long long int uint64_t; 16 | 17 | #endif -------------------------------------------------------------------------------- /chapter7/with_asm/bochsrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 对应真实机器的bios 7 | romimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/BIOS-bochs-latest 8 | # 对应真实机器的VGA bios 9 | vgaromimage: file=/usr/local/Cellar/bochs/2.6.9_2/share/bochs/VGABIOS-lgpl-latest 10 | 11 | # 启动方式 12 | boot: disk 13 | 14 | # 关闭鼠标 15 | mouse: enabled=0 16 | 17 | # 硬盘设置 18 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 19 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 20 | -------------------------------------------------------------------------------- /chapter7/with_asm/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir build 4 | 5 | echo "Creating disk.img..." 6 | bximage -mode=create -hd=10M -q disk.img 7 | 8 | echo "Compiling..." 9 | nasm -I include/ -o build/mbr.bin mbr.asm 10 | nasm -I include/ -o build/loader.bin loader.asm 11 | /usr/local/i386elfgcc/bin/i386-elf-gcc -I lib/ -I kernel/ -c -fno-builtin -o build/main.o kernel/main.c 12 | nasm -f elf -o build/print.o lib/kernel/print.asm 13 | nasm -f elf -o build/kernel.o kernel/kernel.asm 14 | /usr/local/i386elfgcc/bin/i386-elf-gcc -I lib/ -I kernel/ -c -fno-builtin -o build/interrupt.o kernel/interrupt.c 15 | /usr/local/i386elfgcc/bin/i386-elf-gcc -I lib/ -I kernel/ -c -fno-builtin -o build/init.o kernel/init.c 16 | /usr/local/i386elfgcc/bin/i386-elf-ld -Ttext 0xc0001500 -e main -o build/kernel.bin build/main.o build/init.o build/interrupt.o build/print.o build/kernel.o 17 | 18 | echo "Writing mbr, loader and kernel to disk..." 19 | dd if=build/mbr.bin of=disk.img bs=512 count=1 conv=notrunc 20 | dd if=build/loader.bin of=disk.img bs=512 count=4 seek=2 conv=notrunc 21 | dd if=build/kernel.bin of=disk.img bs=512 count=200 seek=9 conv=notrunc 22 | 23 | echo "Now start bochs and have fun!" 24 | bochs -f bochsrc 25 | -------------------------------------------------------------------------------- /chapter7/with_asm/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf disk.img build/ 4 | -------------------------------------------------------------------------------- /chapter7/with_asm/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_START_SECTOR equ 0x9 6 | KERNEL_BIN_BASE_ADDR equ 0x70000 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ; gdt描述符属性 10 | ; 段描述符高23位,表示段界限的粒度为4KB 11 | DESC_G_4K equ 100000000000000000000000b 12 | 13 | ; D/B为,1表示运行在32位模式下 14 | DESC_D_32 equ 10000000000000000000000b 15 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 16 | DESC_L equ 0000000000000000000000b 17 | ; 没有明确的用途,取值随意 18 | DESC_AVL equ 000000000000000000000b 19 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 20 | DESC_LIMIT_CODE2 equ 11110000000000000000b 21 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 22 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 23 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 24 | DESC_P equ 1000000000000000b 25 | DESC_DPL_0 equ 000000000000000b 26 | DESC_DPL_1 equ 010000000000000b 27 | DESC_DPL_2 equ 100000000000000b 28 | DESC_DPL_3 equ 110000000000000b 29 | DESC_S_CODE equ 1000000000000b 30 | DESC_S_DATA equ DESC_S_CODE 31 | DESC_S_sys equ 0000000000000b 32 | DESC_TYPE_CODE equ 100000000000b 33 | DESC_TYPE_DATA equ 001000000000b 34 | 35 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 36 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 39 | 40 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 45 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 46 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 47 | 48 | ; 选择字属性 49 | RPL0 equ 00b 50 | RPL1 equ 01b 51 | RPL2 equ 10b 52 | RPL3 equ 11b 53 | TI_GDT equ 000b 54 | TI_LDT equ 100b 55 | 56 | ; 页表相关属性 57 | PG_P equ 1b 58 | PG_RW_R equ 00b 59 | PG_RW_W equ 10b 60 | PG_US_S equ 000b 61 | PG_US_U equ 100b 62 | 63 | PT_NULL equ 0 -------------------------------------------------------------------------------- /chapter7/with_asm/kernel/global.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_GLOBAL_H 2 | #define _KERNEL_GLOBAL_H 3 | 4 | # include "stdint.h" 5 | 6 | # define RPL0 0 7 | # define RPL1 1 8 | # define RPL2 2 9 | # define RPL3 3 10 | 11 | # define TI_GDT 0 12 | # define TI_LDT 1 13 | 14 | # define SELECTOR_K_CODE ((1 << 3) + (TI_GDT << 2) + RPL0) 15 | # define SELECTOR_K_DATA ((2 << 3) + (TI_GDT << 2) + RPL0) 16 | # define SELECTOR_K_STACK SELECTOR_K_DATA 17 | # define SELECTOR_K_GS ((3 << 3) + (TI_GDT << 2) + RPL0) 18 | 19 | /* IDT描述符属性 */ 20 | # define IDT_DESC_P 1 21 | # define IDT_DESC_DPL0 0 22 | # define IDT_DESC_DPL3 3 23 | # define IDT_DESC_32_TYPE 0xE 24 | # define IDT_DESC_16_TYPE 0x6 25 | 26 | # define IDT_DESC_ATTR_DPL0 \ 27 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL0 << 5) + IDT_DESC_32_TYPE) 28 | 29 | # define IDT_DESC_ATTR_DPL3 \ 30 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL3 << 5) + IDT_DESC_32_TYPE) 31 | 32 | #endif -------------------------------------------------------------------------------- /chapter7/with_asm/kernel/init.c: -------------------------------------------------------------------------------- 1 | # include "init.h" 2 | # include "kernel/print.h" 3 | 4 | void init_all() { 5 | put_str("init_all.\n"); 6 | idt_init(); 7 | } -------------------------------------------------------------------------------- /chapter7/with_asm/kernel/init.h: -------------------------------------------------------------------------------- 1 | void init_all(void); -------------------------------------------------------------------------------- /chapter7/with_asm/kernel/interrupt.c: -------------------------------------------------------------------------------- 1 | # include "stdint.h" 2 | # include "global.h" 3 | # include "io.h" 4 | # include "interrupt.h" 5 | 6 | # define IDT_DESC_CNT 0x21 7 | # define PIC_M_CTRL 0x20 8 | # define PIC_M_DATA 0x21 9 | # define PIC_S_CTRL 0xa0 10 | # define PIC_S_DATA 0xa1 11 | 12 | struct gate_desc { 13 | uint16_t func_offset_low_word; 14 | uint16_t selector; 15 | uint8_t dcount; 16 | 17 | uint8_t attribute; 18 | uint16_t func_offset_high_word; 19 | }; 20 | 21 | static void make_idt_desc(struct gate_desc* p_gdesc, uint8_t attr, intr_handler function); 22 | static struct gate_desc idt[IDT_DESC_CNT]; 23 | 24 | extern intr_handler intr_entry_table[IDT_DESC_CNT]; 25 | 26 | /** 27 | * 创建中断门描述符. 28 | */ 29 | static void make_idt_desc(struct gate_desc* p_gdesc, uint8_t attr, intr_handler function) { 30 | p_gdesc->func_offset_low_word = (uint32_t) function & 0x0000FFFF; 31 | p_gdesc->selector = SELECTOR_K_CODE; 32 | p_gdesc->dcount = 0; 33 | p_gdesc->attribute = attr; 34 | p_gdesc->func_offset_high_word = ((uint32_t) function & 0xFFFF0000) >> 16; 35 | } 36 | 37 | /** 38 | * 初始化中断描述符表. 39 | */ 40 | static void idt_desc_init(void) { 41 | int i; 42 | for (i = 0; i < IDT_DESC_CNT; i++) { 43 | make_idt_desc(&idt[i], IDT_DESC_ATTR_DPL0, intr_entry_table[i]); 44 | } 45 | put_str("idt_desc_init done.\n"); 46 | } 47 | 48 | static void pic_init(void) { 49 | // 初始化主片 50 | outb(PIC_M_CTRL, 0x11); 51 | outb(PIC_M_DATA, 0x20); 52 | 53 | outb(PIC_M_DATA, 0x04); 54 | outb(PIC_M_DATA, 0x01); 55 | 56 | outb(PIC_S_CTRL, 0x11); 57 | outb(PIC_S_DATA, 0x28); 58 | 59 | outb(PIC_S_DATA, 0x02); 60 | outb(PIC_S_DATA, 0x01); 61 | 62 | outb(PIC_M_DATA, 0xfe); 63 | outb(PIC_S_DATA, 0xff); 64 | 65 | put_str("pic_init done.\n"); 66 | } 67 | 68 | void idt_init() { 69 | put_str("idt_init start.\n"); 70 | idt_desc_init(); 71 | pic_init(); 72 | 73 | // 加载idt 74 | uint64_t idt_operand = ((sizeof(idt) - 1) | ((uint64_t) ((uint32_t) idt << 16))); 75 | asm volatile ("lidt %0" : : "m" (idt_operand)); 76 | put_str("idt_init done.\n"); 77 | } -------------------------------------------------------------------------------- /chapter7/with_asm/kernel/interrupt.h: -------------------------------------------------------------------------------- 1 | typedef void* intr_handler; -------------------------------------------------------------------------------- /chapter7/with_asm/kernel/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_IO_H 2 | # define _LIB_IO_H 3 | 4 | # include "stdint.h" 5 | 6 | /** 7 | * 向指定的端口写入一个字节的数据. 8 | */ 9 | static inline void outb(uint16_t port, uint8_t data) { 10 | asm volatile ("outb %b0, %w1" : : "a" (data), "Nd" (port)); 11 | } 12 | 13 | /** 14 | * 将addr起始处的word_cnt个字节写入端口port. 15 | */ 16 | static inline void outsw(uint16_t port, const void* addr, uint32_t word_cnt) { 17 | asm volatile ("cld; rep outsw" : "+S" (addr), "+c" (word_cnt) : "d" (port)); 18 | } 19 | 20 | /** 21 | * 将从端口port读入的一个字节返回. 22 | */ 23 | static inline uint8_t inb(uint16_t port) { 24 | uint8_t data; 25 | asm volatile ("inb %w1, %b0" : "=a" (data) : "Nd" (port)); 26 | return data; 27 | } 28 | 29 | /** 30 | * 将从port读取的word_cnt字节写入addr. 31 | */ 32 | static inline void insw(uint16_t port, void* addr, uint32_t word_cnt) { 33 | asm volatile ("cld; rep insw" : "+D" (addr), "+c" (word_cnt) : "d" (port) : "memory"); 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /chapter7/with_asm/kernel/kernel.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ; 对于CPU会自动压入错误码的中断类型,无需额外的操作 4 | %define ERROR_CODE nop 5 | ; 如果CPU没有压入错误码,为了保持处理逻辑的一致性,我们需要手动压入一个0 6 | %define ZERO push 0 7 | 8 | extern put_str 9 | 10 | section .data 11 | intr_str db "interrupt occur!", 0xa, 0 12 | global intr_entry_table 13 | intr_entry_table: 14 | 15 | ; 中断处理程序宏定义 16 | %macro VECTOR 2 17 | section .text 18 | intr%1entry: 19 | %2 20 | push intr_str 21 | call put_str 22 | add esp, 4 23 | 24 | mov al, 0x20 25 | out 0xa0, al 26 | out 0x20, al 27 | 28 | add esp, 4 29 | iret 30 | 31 | section .data 32 | dd intr%1entry 33 | 34 | %endmacro 35 | 36 | VECTOR 0x00, ZERO 37 | VECTOR 0x01, ZERO 38 | VECTOR 0x02, ZERO 39 | VECTOR 0x03, ZERO 40 | VECTOR 0x04, ZERO 41 | VECTOR 0x05, ZERO 42 | VECTOR 0x06, ZERO 43 | VECTOR 0x07, ZERO 44 | VECTOR 0x08, ZERO 45 | VECTOR 0x09, ZERO 46 | VECTOR 0x0a, ZERO 47 | VECTOR 0x0b, ZERO 48 | VECTOR 0x0c, ZERO 49 | VECTOR 0x0d, ZERO 50 | VECTOR 0x0e, ZERO 51 | VECTOR 0x0f, ZERO 52 | VECTOR 0x10, ZERO 53 | VECTOR 0x11, ZERO 54 | VECTOR 0x12, ZERO 55 | VECTOR 0x13, ZERO 56 | VECTOR 0x14, ZERO 57 | VECTOR 0x15, ZERO 58 | VECTOR 0x16, ZERO 59 | VECTOR 0x17, ZERO 60 | VECTOR 0x18, ZERO 61 | VECTOR 0x19, ZERO 62 | VECTOR 0x1a, ZERO 63 | VECTOR 0x1b, ZERO 64 | VECTOR 0x1c, ZERO 65 | VECTOR 0x1d, ZERO 66 | VECTOR 0x1e, ERROR_CODE 67 | VECTOR 0x1f, ZERO 68 | VECTOR 0x20, ZERO -------------------------------------------------------------------------------- /chapter7/with_asm/kernel/main.c: -------------------------------------------------------------------------------- 1 | # include "kernel/print.h" 2 | # include "init.h" 3 | 4 | void main(void) { 5 | put_str("I am kernel.\n"); 6 | init_all(); 7 | put_str("Init finished.\n"); 8 | asm volatile ("sti"); 9 | put_str("Turn on the interrupt.\n"); 10 | while (1); 11 | } -------------------------------------------------------------------------------- /chapter7/with_asm/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 为print.asm提供方便引用的头文件定义. 3 | */ 4 | #ifndef _LIB_KERNEL_PRINT_H 5 | #define _LIB_KERNEL_PRINT_H 6 | 7 | # include "stdint.h" 8 | 9 | void put_char(uint8_t char_asci); 10 | 11 | /** 12 | * 字符串打印,必须以\0结尾. 13 | */ 14 | void put_str(char* message); 15 | 16 | /** 17 | * 以16进制的形式打印数字. 18 | */ 19 | void put_int(uint32_t num); 20 | 21 | #endif -------------------------------------------------------------------------------- /chapter7/with_asm/lib/stdint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 仿照/usr/include/stdint.h定义我们自己的数据类型. 3 | */ 4 | #ifndef _LIB_STDINT_H 5 | #define _LIB_STDINT_H 6 | 7 | typedef signed char int8_t; 8 | typedef signed short int int16_t; 9 | typedef signed int int32_t; 10 | typedef signed long long int int64_t; 11 | 12 | typedef unsigned char uint8_t; 13 | typedef unsigned short int uint16_t; 14 | typedef unsigned int uint32_t; 15 | typedef unsigned long long int uint64_t; 16 | 17 | #endif -------------------------------------------------------------------------------- /chapter8/assert/bochsrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 启动方式 7 | boot: disk 8 | 9 | # 关闭鼠标 10 | mouse: enabled=0 11 | 12 | # 硬盘设置 13 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 14 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 15 | -------------------------------------------------------------------------------- /chapter8/assert/device/timer.c: -------------------------------------------------------------------------------- 1 | # include "io.h" 2 | # include "kernel/print.h" 3 | 4 | # define IRQ0_FREQUENCY 1000 5 | # define INPUT_FREQUENCY 1193180 6 | # define COUNTER0_VALUE INPUT_FREQUENCY / IRQ0_FREQUENCY 7 | # define COUNTER0_PORT 0x40 8 | # define COUNTER_MODE 2 9 | # define COUNTER0_NO 0 10 | # define READ_WRITE_LATCH 3 11 | # define PIT_CONTROL_PORT 0x43 12 | 13 | 14 | static void frequency_set(uint8_t counter_port, 15 | uint8_t counter_no, 16 | uint8_t rwl, 17 | uint8_t counter_mode, 18 | uint16_t counter_value) { 19 | outb(PIT_CONTROL_PORT, (uint8_t) (counter_no << 6 | rwl << 4 | counter_mode << 1)); 20 | outb(counter_port, (uint8_t) counter_value); 21 | outb(counter_port, (uint8_t) counter_value >> 8); 22 | } 23 | 24 | /** 25 | * 初始化PIT 8253. 26 | */ 27 | void timer_init() { 28 | put_str("timer_init start.\n"); 29 | frequency_set(COUNTER0_PORT, COUNTER0_NO, READ_WRITE_LATCH, COUNTER_MODE, COUNTER0_VALUE); 30 | put_str("timer_init done.\n"); 31 | } -------------------------------------------------------------------------------- /chapter8/assert/device/timer.h: -------------------------------------------------------------------------------- 1 | void timer_init(); -------------------------------------------------------------------------------- /chapter8/assert/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_START_SECTOR equ 0x9 6 | KERNEL_BIN_BASE_ADDR equ 0x70000 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ; gdt描述符属性 10 | ; 段描述符高23位,表示段界限的粒度为4KB 11 | DESC_G_4K equ 100000000000000000000000b 12 | 13 | ; D/B为,1表示运行在32位模式下 14 | DESC_D_32 equ 10000000000000000000000b 15 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 16 | DESC_L equ 0000000000000000000000b 17 | ; 没有明确的用途,取值随意 18 | DESC_AVL equ 000000000000000000000b 19 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 20 | DESC_LIMIT_CODE2 equ 11110000000000000000b 21 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 22 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 23 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 24 | DESC_P equ 1000000000000000b 25 | DESC_DPL_0 equ 000000000000000b 26 | DESC_DPL_1 equ 010000000000000b 27 | DESC_DPL_2 equ 100000000000000b 28 | DESC_DPL_3 equ 110000000000000b 29 | DESC_S_CODE equ 1000000000000b 30 | DESC_S_DATA equ DESC_S_CODE 31 | DESC_S_sys equ 0000000000000b 32 | DESC_TYPE_CODE equ 100000000000b 33 | DESC_TYPE_DATA equ 001000000000b 34 | 35 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 36 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 39 | 40 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 45 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 46 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 47 | 48 | ; 选择字属性 49 | RPL0 equ 00b 50 | RPL1 equ 01b 51 | RPL2 equ 10b 52 | RPL3 equ 11b 53 | TI_GDT equ 000b 54 | TI_LDT equ 100b 55 | 56 | ; 页表相关属性 57 | PG_P equ 1b 58 | PG_RW_R equ 00b 59 | PG_RW_W equ 10b 60 | PG_US_S equ 000b 61 | PG_US_U equ 100b 62 | 63 | PT_NULL equ 0 -------------------------------------------------------------------------------- /chapter8/assert/kernel/debug.c: -------------------------------------------------------------------------------- 1 | # include "debug.h" 2 | # include "kernel/print.h" 3 | # include "interrupt.h" 4 | 5 | void panic_spin(char* filename, int line, const char* func, const char* condition) { 6 | intr_disable(); 7 | 8 | put_str("Something wrong..."); 9 | 10 | put_str("FileName: "); 11 | put_str(filename); 12 | put_char('\n'); 13 | 14 | put_str("Line: "); 15 | put_int(line); 16 | put_char('\n'); 17 | 18 | put_str("Function: "); 19 | put_str(func); 20 | put_char('\n'); 21 | 22 | put_str("Condition: "); 23 | put_str(condition); 24 | put_char('\n'); 25 | 26 | while (1); 27 | } -------------------------------------------------------------------------------- /chapter8/assert/kernel/debug.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_DEBUG_H 2 | # define _KERNEL_DEBUG_H 3 | 4 | void panic_spin(char* filename, int line, const char* func, const char* condition); 5 | 6 | /** 7 | * 当断言被触发时调用. 8 | * _FILE_: 内置宏,表示调用的文件名 9 | * _LINE_: 内置宏,被编译文件的行号 10 | * _func_: 内置宏: 被编译的函数名 11 | * _VA_ARGS_: 函数调用参数 12 | */ 13 | # define PANIC(...) panic_spin (__FILE__, __LINE__, __func__, __VA_ARGS__) 14 | 15 | # ifdef NDEBUG 16 | # define ASSERT(CONDITION) ((void) 0) 17 | # else 18 | # define ASSERT(CONDITION) \ 19 | if (CONDITION) { \ 20 | } else { \ 21 | PANIC(#CONDITION); \ 22 | } 23 | # endif 24 | # endif -------------------------------------------------------------------------------- /chapter8/assert/kernel/global.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_GLOBAL_H 2 | #define _KERNEL_GLOBAL_H 3 | 4 | # include "stdint.h" 5 | 6 | # define RPL0 0 7 | # define RPL1 1 8 | # define RPL2 2 9 | # define RPL3 3 10 | 11 | # define TI_GDT 0 12 | # define TI_LDT 1 13 | 14 | # define SELECTOR_K_CODE ((1 << 3) + (TI_GDT << 2) + RPL0) 15 | # define SELECTOR_K_DATA ((2 << 3) + (TI_GDT << 2) + RPL0) 16 | # define SELECTOR_K_STACK SELECTOR_K_DATA 17 | # define SELECTOR_K_GS ((3 << 3) + (TI_GDT << 2) + RPL0) 18 | 19 | /* IDT描述符属性 */ 20 | # define IDT_DESC_P 1 21 | # define IDT_DESC_DPL0 0 22 | # define IDT_DESC_DPL3 3 23 | # define IDT_DESC_32_TYPE 0xE 24 | # define IDT_DESC_16_TYPE 0x6 25 | 26 | # define IDT_DESC_ATTR_DPL0 \ 27 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL0 << 5) + IDT_DESC_32_TYPE) 28 | 29 | # define IDT_DESC_ATTR_DPL3 \ 30 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL3 << 5) + IDT_DESC_32_TYPE) 31 | 32 | #endif -------------------------------------------------------------------------------- /chapter8/assert/kernel/init.c: -------------------------------------------------------------------------------- 1 | # include "init.h" 2 | # include "kernel/print.h" 3 | # include "timer.h" 4 | 5 | void init_all() { 6 | put_str("init_all.\n"); 7 | idt_init(); 8 | timer_init(); 9 | } -------------------------------------------------------------------------------- /chapter8/assert/kernel/init.h: -------------------------------------------------------------------------------- 1 | void init_all(void); -------------------------------------------------------------------------------- /chapter8/assert/kernel/interrupt.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_INTERRUPT_H 2 | # define _KERNEL_INTERRUPT_H 3 | 4 | # include "stdint.h" 5 | 6 | typedef void* intr_handler; 7 | 8 | void idt_init(void); 9 | 10 | /** 11 | * 中断状态. 12 | */ 13 | enum intr_status { 14 | INTR_OFF, 15 | INTR_ON 16 | }; 17 | 18 | enum intr_status intr_get_status(void); 19 | enum intr_status intr_set_status(enum intr_status); 20 | enum intr_status intr_enable(void); 21 | enum intr_status intr_disable(void); 22 | 23 | # endif 24 | -------------------------------------------------------------------------------- /chapter8/assert/kernel/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_IO_H 2 | # define _LIB_IO_H 3 | 4 | # include "stdint.h" 5 | 6 | /** 7 | * 向指定的端口写入一个字节的数据. 8 | */ 9 | static inline void outb(uint16_t port, uint8_t data) { 10 | asm volatile ("outb %b0, %w1" : : "a" (data), "Nd" (port)); 11 | } 12 | 13 | /** 14 | * 将addr起始处的word_cnt个字节写入端口port. 15 | */ 16 | static inline void outsw(uint16_t port, const void* addr, uint32_t word_cnt) { 17 | asm volatile ("cld; rep outsw" : "+S" (addr), "+c" (word_cnt) : "d" (port)); 18 | } 19 | 20 | /** 21 | * 将从端口port读入的一个字节返回. 22 | */ 23 | static inline uint8_t inb(uint16_t port) { 24 | uint8_t data; 25 | asm volatile ("inb %w1, %b0" : "=a" (data) : "Nd" (port)); 26 | return data; 27 | } 28 | 29 | /** 30 | * 将从port读取的word_cnt字节写入addr. 31 | */ 32 | static inline void insw(uint16_t port, void* addr, uint32_t word_cnt) { 33 | asm volatile ("cld; rep insw" : "+D" (addr), "+c" (word_cnt) : "d" (port) : "memory"); 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /chapter8/assert/kernel/kernel.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ; 对于CPU会自动压入错误码的中断类型,无需额外的操作 4 | %define ERROR_CODE nop 5 | ; 如果CPU没有压入错误码,为了保持处理逻辑的一致性,我们需要手动压入一个0 6 | %define ZERO push 0 7 | 8 | extern put_str 9 | ; 中断处理函数数组 10 | extern idt_table 11 | 12 | section .data 13 | intr_str db "interrupt occur!", 0xa, 0 14 | global intr_entry_table 15 | intr_entry_table: 16 | 17 | ; 中断处理程序宏定义 18 | %macro VECTOR 2 19 | section .text 20 | intr%1entry: 21 | 22 | %2 23 | ; 保存上下文 24 | push ds 25 | push es 26 | push fs 27 | push gs 28 | pushad 29 | 30 | mov al, 0x20 31 | out 0xa0, al 32 | out 0x20, al 33 | 34 | push %1 35 | 36 | ; 调用C的中断处理函数 37 | call [idt_table + 4 * %1] 38 | jmp intr_exit 39 | 40 | section .data 41 | dd intr%1entry 42 | 43 | %endmacro 44 | 45 | section .text 46 | global intr_exit 47 | intr_exit: 48 | add esp, 4 49 | popad 50 | pop gs 51 | pop fs 52 | pop es 53 | pop ds 54 | add esp, 4 55 | iretd 56 | 57 | VECTOR 0x00, ZERO 58 | VECTOR 0x01, ZERO 59 | VECTOR 0x02, ZERO 60 | VECTOR 0x03, ZERO 61 | VECTOR 0x04, ZERO 62 | VECTOR 0x05, ZERO 63 | VECTOR 0x06, ZERO 64 | VECTOR 0x07, ZERO 65 | VECTOR 0x08, ZERO 66 | VECTOR 0x09, ZERO 67 | VECTOR 0x0a, ZERO 68 | VECTOR 0x0b, ZERO 69 | VECTOR 0x0c, ZERO 70 | VECTOR 0x0d, ZERO 71 | VECTOR 0x0e, ZERO 72 | VECTOR 0x0f, ZERO 73 | VECTOR 0x10, ZERO 74 | VECTOR 0x11, ZERO 75 | VECTOR 0x12, ZERO 76 | VECTOR 0x13, ZERO 77 | VECTOR 0x14, ZERO 78 | VECTOR 0x15, ZERO 79 | VECTOR 0x16, ZERO 80 | VECTOR 0x17, ZERO 81 | VECTOR 0x18, ZERO 82 | VECTOR 0x19, ZERO 83 | VECTOR 0x1a, ZERO 84 | VECTOR 0x1b, ZERO 85 | VECTOR 0x1c, ZERO 86 | VECTOR 0x1d, ZERO 87 | VECTOR 0x1e, ERROR_CODE 88 | VECTOR 0x1f, ZERO 89 | VECTOR 0x20, ZERO -------------------------------------------------------------------------------- /chapter8/assert/kernel/main.c: -------------------------------------------------------------------------------- 1 | # include "kernel/print.h" 2 | # include "init.h" 3 | # include "debug.h" 4 | 5 | int main(void) { 6 | put_str("I am kernel.\n"); 7 | init_all(); 8 | put_str("Init finished.\n"); 9 | 10 | ASSERT(1 == 2); 11 | 12 | while (1); 13 | return 0; 14 | } -------------------------------------------------------------------------------- /chapter8/assert/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 为print.asm提供方便引用的头文件定义. 3 | */ 4 | #ifndef _LIB_KERNEL_PRINT_H 5 | #define _LIB_KERNEL_PRINT_H 6 | 7 | # include "stdint.h" 8 | 9 | void put_char(uint8_t char_asci); 10 | 11 | /** 12 | * 字符串打印,必须以\0结尾. 13 | */ 14 | void put_str(char* message); 15 | 16 | /** 17 | * 以16进制的形式打印数字. 18 | */ 19 | void put_int(uint32_t num); 20 | 21 | #endif -------------------------------------------------------------------------------- /chapter8/assert/lib/stdint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 仿照/usr/include/stdint.h定义我们自己的数据类型. 3 | */ 4 | #ifndef _LIB_STDINT_H 5 | #define _LIB_STDINT_H 6 | 7 | typedef signed char int8_t; 8 | typedef signed short int int16_t; 9 | typedef signed int int32_t; 10 | typedef signed long long int int64_t; 11 | 12 | typedef unsigned char uint8_t; 13 | typedef unsigned short int uint16_t; 14 | typedef unsigned int uint32_t; 15 | typedef unsigned long long int uint64_t; 16 | 17 | #endif -------------------------------------------------------------------------------- /chapter8/assert/makefile: -------------------------------------------------------------------------------- 1 | BUILD_DIR = build 2 | ENTRY_POINT = 0xc0001500 3 | AS = nasm 4 | CC = gcc 5 | LD = ld 6 | LIB = -I lib/ -I kernel/ -I device/ 7 | ASFLAGS = -f elf 8 | ASIB = -I include/ 9 | CFLAGS = -Wall -m32 -fno-stack-protector $(LIB) -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes 10 | LDFLAGS = -m elf_i386 -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_DIR)/kernel.map 11 | OBJS = $(BUILD_DIR)/main.o $(BUILD_DIR)/init.o $(BUILD_DIR)/interrupt.o $(BUILD_DIR)/timer.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o $(BUILD_DIR)/debug.o 12 | 13 | # C代码编译 14 | $(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h lib/stdint.h kernel/init.h 15 | $(CC) $(CFLAGS) $< -o $@ 16 | 17 | $(BUILD_DIR)/init.o: kernel/init.c kernel/init.h lib/kernel/print.h lib/stdint.h kernel/interrupt.h device/timer.h 18 | $(CC) $(CFLAGS) $< -o $@ 19 | 20 | $(BUILD_DIR)/interrupt.o: kernel/interrupt.c kernel/interrupt.h lib/stdint.h kernel/global.h kernel/io.h lib/kernel/print.h 21 | $(CC) $(CFLAGS) $< -o $@ 22 | 23 | $(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/stdint.h kernel/io.h lib/kernel/print.h 24 | $(CC) $(CFLAGS) $< -o $@ 25 | 26 | $(BUILD_DIR)/debug.o: kernel/debug.c kernel/debug.h lib/kernel/print.h lib/stdint.h kernel/interrupt.h 27 | $(CC) $(CFLAGS) $< -o $@ 28 | 29 | # 编译loader和mbr 30 | $(BUILD_DIR)/mbr.bin: mbr.asm 31 | $(AS) $(ASIB) $< -o $@ 32 | 33 | $(BUILD_DIR)/loader.bin: loader.asm 34 | $(AS) $(ASIB) $< -o $@ 35 | 36 | # 编译汇编 37 | $(BUILD_DIR)/kernel.o: kernel/kernel.asm 38 | $(AS) $(ASFLAGS) $< -o $@ 39 | 40 | $(BUILD_DIR)/print.o: lib/kernel/print.asm 41 | $(AS) $(ASFLAGS) $< -o $@ 42 | 43 | # 链接 44 | $(BUILD_DIR)/kernel.bin: $(OBJS) 45 | $(LD) $(LDFLAGS) $^ -o $@ 46 | 47 | .PHONY: mk_dir hd clean all 48 | 49 | mk_dir: 50 | if [ ! -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR); fi 51 | bximage -hd -mode=flat -size=10 -q disk.img 52 | echo "Create image done." 53 | 54 | hd: 55 | dd if=$(BUILD_DIR)/mbr.bin of=disk.img bs=512 count=1 conv=notrunc 56 | dd if=$(BUILD_DIR)/loader.bin of=disk.img bs=512 count=4 seek=2 conv=notrunc 57 | dd if=$(BUILD_DIR)/kernel.bin of=disk.img bs=512 count=200 seek=9 conv=notrunc 58 | 59 | clean: 60 | rm -rf disk.img $(BUILD_DIR) 61 | 62 | build: $(BUILD_DIR)/mbr.bin $(BUILD_DIR)/loader.bin $(BUILD_DIR)/kernel.bin 63 | 64 | all: mk_dir build hd -------------------------------------------------------------------------------- /chapter8/memory_manager/bochsrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 启动方式 7 | boot: disk 8 | 9 | # 关闭鼠标 10 | mouse: enabled=0 11 | 12 | # 硬盘设置 13 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 14 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 15 | -------------------------------------------------------------------------------- /chapter8/memory_manager/device/timer.c: -------------------------------------------------------------------------------- 1 | # include "io.h" 2 | # include "kernel/print.h" 3 | 4 | # define IRQ0_FREQUENCY 1000 5 | # define INPUT_FREQUENCY 1193180 6 | # define COUNTER0_VALUE INPUT_FREQUENCY / IRQ0_FREQUENCY 7 | # define COUNTER0_PORT 0x40 8 | # define COUNTER_MODE 2 9 | # define COUNTER0_NO 0 10 | # define READ_WRITE_LATCH 3 11 | # define PIT_CONTROL_PORT 0x43 12 | 13 | 14 | static void frequency_set(uint8_t counter_port, 15 | uint8_t counter_no, 16 | uint8_t rwl, 17 | uint8_t counter_mode, 18 | uint16_t counter_value) { 19 | outb(PIT_CONTROL_PORT, (uint8_t) (counter_no << 6 | rwl << 4 | counter_mode << 1)); 20 | outb(counter_port, (uint8_t) counter_value); 21 | outb(counter_port, (uint8_t) counter_value >> 8); 22 | } 23 | 24 | /** 25 | * 初始化PIT 8253. 26 | */ 27 | void timer_init() { 28 | put_str("timer_init start.\n"); 29 | frequency_set(COUNTER0_PORT, COUNTER0_NO, READ_WRITE_LATCH, COUNTER_MODE, COUNTER0_VALUE); 30 | put_str("timer_init done.\n"); 31 | } -------------------------------------------------------------------------------- /chapter8/memory_manager/device/timer.h: -------------------------------------------------------------------------------- 1 | void timer_init(); -------------------------------------------------------------------------------- /chapter8/memory_manager/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_START_SECTOR equ 0x9 6 | KERNEL_BIN_BASE_ADDR equ 0x70000 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ; gdt描述符属性 10 | ; 段描述符高23位,表示段界限的粒度为4KB 11 | DESC_G_4K equ 100000000000000000000000b 12 | 13 | ; D/B为,1表示运行在32位模式下 14 | DESC_D_32 equ 10000000000000000000000b 15 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 16 | DESC_L equ 0000000000000000000000b 17 | ; 没有明确的用途,取值随意 18 | DESC_AVL equ 000000000000000000000b 19 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 20 | DESC_LIMIT_CODE2 equ 11110000000000000000b 21 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 22 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 23 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 24 | DESC_P equ 1000000000000000b 25 | DESC_DPL_0 equ 000000000000000b 26 | DESC_DPL_1 equ 010000000000000b 27 | DESC_DPL_2 equ 100000000000000b 28 | DESC_DPL_3 equ 110000000000000b 29 | DESC_S_CODE equ 1000000000000b 30 | DESC_S_DATA equ DESC_S_CODE 31 | DESC_S_sys equ 0000000000000b 32 | DESC_TYPE_CODE equ 100000000000b 33 | DESC_TYPE_DATA equ 001000000000b 34 | 35 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 36 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 39 | 40 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 45 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 46 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 47 | 48 | ; 选择字属性 49 | RPL0 equ 00b 50 | RPL1 equ 01b 51 | RPL2 equ 10b 52 | RPL3 equ 11b 53 | TI_GDT equ 000b 54 | TI_LDT equ 100b 55 | 56 | ; 页表相关属性 57 | PG_P equ 1b 58 | PG_RW_R equ 00b 59 | PG_RW_W equ 10b 60 | PG_US_S equ 000b 61 | PG_US_U equ 100b 62 | 63 | PT_NULL equ 0 -------------------------------------------------------------------------------- /chapter8/memory_manager/kernel/debug.c: -------------------------------------------------------------------------------- 1 | # include "debug.h" 2 | # include "kernel/print.h" 3 | # include "interrupt.h" 4 | 5 | void panic_spin(char* filename, int line, const char* func, const char* condition) { 6 | intr_disable(); 7 | 8 | put_str("Something wrong..."); 9 | 10 | put_str("FileName: "); 11 | put_str(filename); 12 | put_char('\n'); 13 | 14 | put_str("Line: "); 15 | put_int(line); 16 | put_char('\n'); 17 | 18 | put_str("Function: "); 19 | put_str(func); 20 | put_char('\n'); 21 | 22 | put_str("Condition: "); 23 | put_str(condition); 24 | put_char('\n'); 25 | 26 | while (1); 27 | } -------------------------------------------------------------------------------- /chapter8/memory_manager/kernel/debug.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_DEBUG_H 2 | # define _KERNEL_DEBUG_H 3 | 4 | void panic_spin(char* filename, int line, const char* func, const char* condition); 5 | 6 | /** 7 | * 当断言被触发时调用. 8 | * _FILE_: 内置宏,表示调用的文件名 9 | * _LINE_: 内置宏,被编译文件的行号 10 | * _func_: 内置宏: 被编译的函数名 11 | * _VA_ARGS_: 函数调用参数 12 | */ 13 | # define PANIC(...) panic_spin (__FILE__, __LINE__, __func__, __VA_ARGS__) 14 | 15 | # ifdef NDEBUG 16 | # define ASSERT(CONDITION) ((void) 0) 17 | # else 18 | # define ASSERT(CONDITION) \ 19 | if (CONDITION) { \ 20 | } else { \ 21 | PANIC(#CONDITION); \ 22 | } 23 | # endif 24 | # endif -------------------------------------------------------------------------------- /chapter8/memory_manager/kernel/global.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_GLOBAL_H 2 | #define _KERNEL_GLOBAL_H 3 | 4 | # include "stdint.h" 5 | 6 | # define RPL0 0 7 | # define RPL1 1 8 | # define RPL2 2 9 | # define RPL3 3 10 | 11 | # define TI_GDT 0 12 | # define TI_LDT 1 13 | 14 | # define SELECTOR_K_CODE ((1 << 3) + (TI_GDT << 2) + RPL0) 15 | # define SELECTOR_K_DATA ((2 << 3) + (TI_GDT << 2) + RPL0) 16 | # define SELECTOR_K_STACK SELECTOR_K_DATA 17 | # define SELECTOR_K_GS ((3 << 3) + (TI_GDT << 2) + RPL0) 18 | 19 | /* IDT描述符属性 */ 20 | # define IDT_DESC_P 1 21 | # define IDT_DESC_DPL0 0 22 | # define IDT_DESC_DPL3 3 23 | # define IDT_DESC_32_TYPE 0xE 24 | # define IDT_DESC_16_TYPE 0x6 25 | 26 | # define IDT_DESC_ATTR_DPL0 \ 27 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL0 << 5) + IDT_DESC_32_TYPE) 28 | 29 | # define IDT_DESC_ATTR_DPL3 \ 30 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL3 << 5) + IDT_DESC_32_TYPE) 31 | 32 | # define NULL 0 33 | 34 | #endif -------------------------------------------------------------------------------- /chapter8/memory_manager/kernel/init.c: -------------------------------------------------------------------------------- 1 | # include "init.h" 2 | # include "kernel/print.h" 3 | # include "timer.h" 4 | # include "memory.h" 5 | 6 | void init_all() { 7 | put_str("init_all.\n"); 8 | idt_init(); 9 | timer_init(); 10 | mem_init(); 11 | } -------------------------------------------------------------------------------- /chapter8/memory_manager/kernel/init.h: -------------------------------------------------------------------------------- 1 | void init_all(void); -------------------------------------------------------------------------------- /chapter8/memory_manager/kernel/interrupt.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_INTERRUPT_H 2 | # define _KERNEL_INTERRUPT_H 3 | 4 | # include "stdint.h" 5 | 6 | typedef void* intr_handler; 7 | 8 | void idt_init(void); 9 | 10 | /** 11 | * 中断状态. 12 | */ 13 | enum intr_status { 14 | INTR_OFF, 15 | INTR_ON 16 | }; 17 | 18 | enum intr_status intr_get_status(void); 19 | enum intr_status intr_set_status(enum intr_status); 20 | enum intr_status intr_enable(void); 21 | enum intr_status intr_disable(void); 22 | 23 | # endif 24 | -------------------------------------------------------------------------------- /chapter8/memory_manager/kernel/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_IO_H 2 | # define _LIB_IO_H 3 | 4 | # include "stdint.h" 5 | 6 | /** 7 | * 向指定的端口写入一个字节的数据. 8 | */ 9 | static inline void outb(uint16_t port, uint8_t data) { 10 | asm volatile ("outb %b0, %w1" : : "a" (data), "Nd" (port)); 11 | } 12 | 13 | /** 14 | * 将addr起始处的word_cnt个字节写入端口port. 15 | */ 16 | static inline void outsw(uint16_t port, const void* addr, uint32_t word_cnt) { 17 | asm volatile ("cld; rep outsw" : "+S" (addr), "+c" (word_cnt) : "d" (port)); 18 | } 19 | 20 | /** 21 | * 将从端口port读入的一个字节返回. 22 | */ 23 | static inline uint8_t inb(uint16_t port) { 24 | uint8_t data; 25 | asm volatile ("inb %w1, %b0" : "=a" (data) : "Nd" (port)); 26 | return data; 27 | } 28 | 29 | /** 30 | * 将从port读取的word_cnt字节写入addr. 31 | */ 32 | static inline void insw(uint16_t port, void* addr, uint32_t word_cnt) { 33 | asm volatile ("cld; rep insw" : "+D" (addr), "+c" (word_cnt) : "d" (port) : "memory"); 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /chapter8/memory_manager/kernel/kernel.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ; 对于CPU会自动压入错误码的中断类型,无需额外的操作 4 | %define ERROR_CODE nop 5 | ; 如果CPU没有压入错误码,为了保持处理逻辑的一致性,我们需要手动压入一个0 6 | %define ZERO push 0 7 | 8 | extern put_str 9 | ; 中断处理函数数组 10 | extern idt_table 11 | 12 | section .data 13 | intr_str db "interrupt occur!", 0xa, 0 14 | global intr_entry_table 15 | intr_entry_table: 16 | 17 | ; 中断处理程序宏定义 18 | %macro VECTOR 2 19 | section .text 20 | intr%1entry: 21 | 22 | %2 23 | ; 保存上下文 24 | push ds 25 | push es 26 | push fs 27 | push gs 28 | pushad 29 | 30 | mov al, 0x20 31 | out 0xa0, al 32 | out 0x20, al 33 | 34 | push %1 35 | 36 | ; 调用C的中断处理函数 37 | call [idt_table + 4 * %1] 38 | jmp intr_exit 39 | 40 | section .data 41 | dd intr%1entry 42 | 43 | %endmacro 44 | 45 | section .text 46 | global intr_exit 47 | intr_exit: 48 | add esp, 4 49 | popad 50 | pop gs 51 | pop fs 52 | pop es 53 | pop ds 54 | add esp, 4 55 | iretd 56 | 57 | VECTOR 0x00, ZERO 58 | VECTOR 0x01, ZERO 59 | VECTOR 0x02, ZERO 60 | VECTOR 0x03, ZERO 61 | VECTOR 0x04, ZERO 62 | VECTOR 0x05, ZERO 63 | VECTOR 0x06, ZERO 64 | VECTOR 0x07, ZERO 65 | VECTOR 0x08, ZERO 66 | VECTOR 0x09, ZERO 67 | VECTOR 0x0a, ZERO 68 | VECTOR 0x0b, ZERO 69 | VECTOR 0x0c, ZERO 70 | VECTOR 0x0d, ZERO 71 | VECTOR 0x0e, ZERO 72 | VECTOR 0x0f, ZERO 73 | VECTOR 0x10, ZERO 74 | VECTOR 0x11, ZERO 75 | VECTOR 0x12, ZERO 76 | VECTOR 0x13, ZERO 77 | VECTOR 0x14, ZERO 78 | VECTOR 0x15, ZERO 79 | VECTOR 0x16, ZERO 80 | VECTOR 0x17, ZERO 81 | VECTOR 0x18, ZERO 82 | VECTOR 0x19, ZERO 83 | VECTOR 0x1a, ZERO 84 | VECTOR 0x1b, ZERO 85 | VECTOR 0x1c, ZERO 86 | VECTOR 0x1d, ZERO 87 | VECTOR 0x1e, ERROR_CODE 88 | VECTOR 0x1f, ZERO 89 | VECTOR 0x20, ZERO -------------------------------------------------------------------------------- /chapter8/memory_manager/kernel/main.c: -------------------------------------------------------------------------------- 1 | # include "kernel/print.h" 2 | # include "init.h" 3 | # include "debug.h" 4 | # include "memory.h" 5 | 6 | int main(void) { 7 | put_str("I am kernel.\n"); 8 | init_all(); 9 | put_str("Init done.\n"); 10 | 11 | void* vaddr = get_kernel_pages(3); 12 | put_str("\nKernel memory virtual page start address: "); 13 | put_int((uint32_t) vaddr); 14 | put_char('\n'); 15 | 16 | while (1); 17 | return 0; 18 | } -------------------------------------------------------------------------------- /chapter8/memory_manager/kernel/memory.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_MEMORY_H 2 | # define _KERNEL_MEMORY_H 3 | 4 | # include "stdint.h" 5 | # include "bitmap.h" 6 | 7 | // 存在标志 8 | # define PG_P_1 1 9 | # define PG_P_0 0 10 | // 只读 11 | # define PG_RW_R 0 12 | // 可写 13 | # define PG_RW_W 2 14 | // 系统级 15 | # define PG_US_S 0 16 | # define PG_US_U 4 17 | 18 | /** 19 | * 内存池类型标志. 20 | */ 21 | enum pool_flags { 22 | // 内核类型 23 | PF_KERNEL = 1, 24 | PF_USER = 2 25 | }; 26 | 27 | struct virtual_addr { 28 | struct bitmap vaddr_bitmap; 29 | // 虚拟内存的起始地址 30 | uint32_t vaddr_start; 31 | }; 32 | 33 | extern struct pool kernel_pool, user_pool; 34 | 35 | void mem_init(void); 36 | 37 | void* get_kernel_pages(uint32_t page_count); 38 | 39 | void* malloc_page(enum pool_flags pf, uint32_t page_count); 40 | 41 | # endif -------------------------------------------------------------------------------- /chapter8/memory_manager/lib/bitmap.c: -------------------------------------------------------------------------------- 1 | # include "bitmap.h" 2 | # include "stdint.h" 3 | # include "string.h" 4 | # include "kernel/print.h" 5 | # include "interrupt.h" 6 | # include "debug.h" 7 | 8 | void bitmap_init(struct bitmap* btmap) { 9 | memset(btmap->bits, 0, btmap->btmp_bytes_len); 10 | } 11 | 12 | /** 13 | * 检测指定位是否为1,如果是,返回1. 14 | */ 15 | int bitmap_scan_test(struct bitmap* btmap, uint32_t index) { 16 | uint32_t byte_index = (index / 8); 17 | uint32_t bit_odd = byte_index % 8; 18 | 19 | return (btmap->bits[byte_index] & BITMAP_MASK << bit_odd); 20 | } 21 | 22 | /** 23 | * 在位图中申请连续的cnt个位. 24 | */ 25 | int bitmap_scan(struct bitmap* btmap, uint32_t cnt) { 26 | uint32_t idx_byte = 0; 27 | 28 | // 以字节为单位进行查找 29 | while ((0xff == btmap->bits[idx_byte]) && idx_byte < btmap->btmp_bytes_len) { 30 | ++idx_byte; 31 | } 32 | 33 | // 没有找到 34 | if (idx_byte == btmap->btmp_bytes_len) { 35 | return -1; 36 | } 37 | 38 | // 找到了一个字节不全为1,那么在字节内部再次进行查找具体的起使位 39 | int idx_bit = 0; 40 | while ((uint8_t) BITMAP_MASK << idx_bit & btmap->bits[idx_byte]) { 41 | ++idx_bit; 42 | } 43 | 44 | // 起始位 45 | int bit_idx_start = (idx_byte * 8 + idx_bit); 46 | if (cnt == 1) { 47 | return bit_idx_start; 48 | } 49 | 50 | uint32_t bit_left = (btmap->btmp_bytes_len * 8 - bit_idx_start); 51 | uint32_t count = 1; 52 | 53 | uint32_t next_bit = bit_idx_start + 1; 54 | 55 | bit_idx_start = -1; 56 | while (bit_left-- > 0) { 57 | if (!(bitmap_scan_test(btmap, next_bit))) { 58 | ++count; 59 | } else { 60 | count = 0; 61 | } 62 | 63 | if (count == cnt) { 64 | bit_idx_start = (next_bit - cnt + 1); 65 | break; 66 | } 67 | 68 | next_bit++; 69 | } 70 | 71 | return bit_idx_start; 72 | } 73 | 74 | void bitmap_set(struct bitmap* btmap, uint32_t index, int8_t value) { 75 | ASSERT(value == 0 || value == 1); 76 | 77 | uint32_t byte_index = index / 8; 78 | uint32_t bit_odd = index % 8; 79 | 80 | if (value) { 81 | btmap->bits[byte_index] |= (BITMAP_MASK << bit_odd); 82 | } else { 83 | btmap->bits[byte_index] &= ~(BITMAP_MASK << bit_odd); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /chapter8/memory_manager/lib/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_KERNEL_BITMAP_H 2 | #define _LIB_KERNEL_BITMAP_H 3 | 4 | # include "global.h" 5 | 6 | # define BITMAP_MASK 1 7 | 8 | struct bitmap { 9 | uint32_t btmp_bytes_len; 10 | uint8_t* bits; 11 | }; 12 | 13 | void bitmap_init(struct bitmap* btmap); 14 | 15 | int bitmap_scan_test(struct bitmap* btmap, uint32_t bit_idx); 16 | 17 | int bitmap_scan(struct bitmap* btmap, uint32_t cnt); 18 | 19 | void bitmap_set(struct bitmap* btmap, uint32_t index, int8_t value); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /chapter8/memory_manager/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 为print.asm提供方便引用的头文件定义. 3 | */ 4 | #ifndef _LIB_KERNEL_PRINT_H 5 | #define _LIB_KERNEL_PRINT_H 6 | 7 | # include "stdint.h" 8 | 9 | void put_char(uint8_t char_asci); 10 | 11 | /** 12 | * 字符串打印,必须以\0结尾. 13 | */ 14 | void put_str(char* message); 15 | 16 | /** 17 | * 以16进制的形式打印数字. 18 | */ 19 | void put_int(uint32_t num); 20 | 21 | #endif -------------------------------------------------------------------------------- /chapter8/memory_manager/lib/stdint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 仿照/usr/include/stdint.h定义我们自己的数据类型. 3 | */ 4 | #ifndef _LIB_STDINT_H 5 | #define _LIB_STDINT_H 6 | 7 | typedef signed char int8_t; 8 | typedef signed short int int16_t; 9 | typedef signed int int32_t; 10 | typedef signed long long int int64_t; 11 | 12 | typedef unsigned char uint8_t; 13 | typedef unsigned short int uint16_t; 14 | typedef unsigned int uint32_t; 15 | typedef unsigned long long int uint64_t; 16 | 17 | #endif -------------------------------------------------------------------------------- /chapter8/memory_manager/lib/string.h: -------------------------------------------------------------------------------- 1 | # ifndef _LIB_STRING_H 2 | # define _LIB_STRING_H 3 | 4 | # include "global.h" 5 | # include "debug.h" 6 | 7 | void memset(void* address, uint8_t value, uint32_t size); 8 | void memcpy(void* dst, const void* src, uint32_t size); 9 | int memcmp(const void* left, const void* right, uint32_t size); 10 | char* strcpy(char* dst, const char* src); 11 | uint32_t strlen(const char* str); 12 | int8_t strcmp(const char* left, const char* right); 13 | char* strchr(const char* str, const uint8_t c); 14 | char* strrchr(const char* str, const uint8_t c); 15 | char* strcat(char* dst, const char* src); 16 | uint32_t strchrs(const char* str, const uint8_t c); 17 | 18 | # endif -------------------------------------------------------------------------------- /chapter9/thread_schedule/bochsrc.bxrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 启动方式 7 | boot: disk 8 | 9 | # 关闭鼠标 10 | mouse: enabled=0 11 | 12 | # 硬盘设置 13 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 14 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 15 | -------------------------------------------------------------------------------- /chapter9/thread_schedule/device/timer.c: -------------------------------------------------------------------------------- 1 | # include "io.h" 2 | # include "kernel/print.h" 3 | # include "interrupt.h" 4 | # include "thread.h" 5 | # include "debug.h" 6 | 7 | # define IRQ0_FREQUENCY 1000 8 | # define INPUT_FREQUENCY 1193180 9 | # define COUNTER0_VALUE INPUT_FREQUENCY / IRQ0_FREQUENCY 10 | # define COUNTER0_PORT 0x40 11 | # define COUNTER_MODE 2 12 | # define COUNTER0_NO 0 13 | # define READ_WRITE_LATCH 3 14 | # define PIT_CONTROL_PORT 0x43 15 | 16 | /** 17 | * 内核自开启中断后所有的嘀嗒数. 18 | */ 19 | uint32_t ticks; 20 | 21 | static void frequency_set(uint8_t counter_port, 22 | uint8_t counter_no, 23 | uint8_t rwl, 24 | uint8_t counter_mode, 25 | uint16_t counter_value) { 26 | outb(PIT_CONTROL_PORT, (uint8_t) (counter_no << 6 | rwl << 4 | counter_mode << 1)); 27 | outb(counter_port, (uint8_t) counter_value); 28 | outb(counter_port, (uint8_t) counter_value >> 8); 29 | } 30 | 31 | static void intr_timer_handler(void) { 32 | struct task_struct* cur_thread = running_thread(); 33 | 34 | ASSERT(cur_thread->stack_magic == 0x77777777); 35 | 36 | cur_thread->elaspsed_ticks++; 37 | ticks++; 38 | 39 | if (cur_thread->ticks == 0) { 40 | schedule(); 41 | } else { 42 | cur_thread->ticks--; 43 | } 44 | } 45 | 46 | /** 47 | * 初始化PIT 8253. 48 | */ 49 | void timer_init() { 50 | put_str("timer_init start.\n"); 51 | frequency_set(COUNTER0_PORT, COUNTER0_NO, READ_WRITE_LATCH, COUNTER_MODE, COUNTER0_VALUE); 52 | register_handler(0x20, intr_timer_handler); 53 | put_str("timer_init done.\n"); 54 | } -------------------------------------------------------------------------------- /chapter9/thread_schedule/device/timer.h: -------------------------------------------------------------------------------- 1 | void timer_init(); -------------------------------------------------------------------------------- /chapter9/thread_schedule/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_START_SECTOR equ 0x9 6 | KERNEL_BIN_BASE_ADDR equ 0x70000 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ; gdt描述符属性 10 | ; 段描述符高23位,表示段界限的粒度为4KB 11 | DESC_G_4K equ 100000000000000000000000b 12 | 13 | ; D/B为,1表示运行在32位模式下 14 | DESC_D_32 equ 10000000000000000000000b 15 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 16 | DESC_L equ 0000000000000000000000b 17 | ; 没有明确的用途,取值随意 18 | DESC_AVL equ 000000000000000000000b 19 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 20 | DESC_LIMIT_CODE2 equ 11110000000000000000b 21 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 22 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 23 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 24 | DESC_P equ 1000000000000000b 25 | DESC_DPL_0 equ 000000000000000b 26 | DESC_DPL_1 equ 010000000000000b 27 | DESC_DPL_2 equ 100000000000000b 28 | DESC_DPL_3 equ 110000000000000b 29 | DESC_S_CODE equ 1000000000000b 30 | DESC_S_DATA equ DESC_S_CODE 31 | DESC_S_sys equ 0000000000000b 32 | DESC_TYPE_CODE equ 100000000000b 33 | DESC_TYPE_DATA equ 001000000000b 34 | 35 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 36 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 39 | 40 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 45 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 46 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 47 | 48 | ; 选择字属性 49 | RPL0 equ 00b 50 | RPL1 equ 01b 51 | RPL2 equ 10b 52 | RPL3 equ 11b 53 | TI_GDT equ 000b 54 | TI_LDT equ 100b 55 | 56 | ; 页表相关属性 57 | PG_P equ 1b 58 | PG_RW_R equ 00b 59 | PG_RW_W equ 10b 60 | PG_US_S equ 000b 61 | PG_US_U equ 100b 62 | 63 | PT_NULL equ 0 -------------------------------------------------------------------------------- /chapter9/thread_schedule/kernel/debug.c: -------------------------------------------------------------------------------- 1 | # include "debug.h" 2 | # include "kernel/print.h" 3 | # include "interrupt.h" 4 | 5 | void panic_spin(char* filename, int line, const char* func, const char* condition) { 6 | intr_disable(); 7 | 8 | put_str("Something wrong..."); 9 | 10 | put_str("FileName: "); 11 | put_str(filename); 12 | put_char('\n'); 13 | 14 | put_str("Line: "); 15 | put_int(line); 16 | put_char('\n'); 17 | 18 | put_str("Function: "); 19 | put_str(func); 20 | put_char('\n'); 21 | 22 | put_str("Condition: "); 23 | put_str(condition); 24 | put_char('\n'); 25 | 26 | while (1); 27 | } -------------------------------------------------------------------------------- /chapter9/thread_schedule/kernel/debug.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_DEBUG_H 2 | # define _KERNEL_DEBUG_H 3 | 4 | void panic_spin(char* filename, int line, const char* func, const char* condition); 5 | 6 | /** 7 | * 当断言被触发时调用. 8 | * _FILE_: 内置宏,表示调用的文件名 9 | * _LINE_: 内置宏,被编译文件的行号 10 | * _func_: 内置宏: 被编译的函数名 11 | * _VA_ARGS_: 函数调用参数 12 | */ 13 | # define PANIC(...) panic_spin (__FILE__, __LINE__, __func__, __VA_ARGS__) 14 | 15 | # ifdef NDEBUG 16 | # define ASSERT(CONDITION) ((void) 0) 17 | # else 18 | # define ASSERT(CONDITION) \ 19 | if (CONDITION) { \ 20 | } else { \ 21 | PANIC(#CONDITION); \ 22 | } 23 | # endif 24 | # endif -------------------------------------------------------------------------------- /chapter9/thread_schedule/kernel/global.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_GLOBAL_H 2 | #define _KERNEL_GLOBAL_H 3 | 4 | # include "stdint.h" 5 | 6 | # define RPL0 0 7 | # define RPL1 1 8 | # define RPL2 2 9 | # define RPL3 3 10 | 11 | # define TI_GDT 0 12 | # define TI_LDT 1 13 | 14 | # define SELECTOR_K_CODE ((1 << 3) + (TI_GDT << 2) + RPL0) 15 | # define SELECTOR_K_DATA ((2 << 3) + (TI_GDT << 2) + RPL0) 16 | # define SELECTOR_K_STACK SELECTOR_K_DATA 17 | # define SELECTOR_K_GS ((3 << 3) + (TI_GDT << 2) + RPL0) 18 | 19 | /* IDT描述符属性 */ 20 | # define IDT_DESC_P 1 21 | # define IDT_DESC_DPL0 0 22 | # define IDT_DESC_DPL3 3 23 | # define IDT_DESC_32_TYPE 0xE 24 | # define IDT_DESC_16_TYPE 0x6 25 | 26 | # define IDT_DESC_ATTR_DPL0 \ 27 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL0 << 5) + IDT_DESC_32_TYPE) 28 | 29 | # define IDT_DESC_ATTR_DPL3 \ 30 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL3 << 5) + IDT_DESC_32_TYPE) 31 | 32 | # define NULL 0 33 | 34 | #endif -------------------------------------------------------------------------------- /chapter9/thread_schedule/kernel/init.c: -------------------------------------------------------------------------------- 1 | # include "init.h" 2 | # include "kernel/print.h" 3 | # include "timer.h" 4 | # include "memory.h" 5 | # include "thread.h" 6 | 7 | void init_all() { 8 | put_str("init_all.\n"); 9 | idt_init(); 10 | mem_init(); 11 | thread_init(); 12 | timer_init(); 13 | } -------------------------------------------------------------------------------- /chapter9/thread_schedule/kernel/init.h: -------------------------------------------------------------------------------- 1 | void init_all(void); -------------------------------------------------------------------------------- /chapter9/thread_schedule/kernel/interrupt.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_INTERRUPT_H 2 | # define _KERNEL_INTERRUPT_H 3 | 4 | # include "stdint.h" 5 | 6 | typedef void* intr_handler; 7 | 8 | void idt_init(void); 9 | 10 | /** 11 | * 中断状态. 12 | */ 13 | enum intr_status { 14 | INTR_OFF, 15 | INTR_ON 16 | }; 17 | 18 | enum intr_status intr_get_status(void); 19 | enum intr_status intr_set_status(enum intr_status); 20 | enum intr_status intr_enable(void); 21 | enum intr_status intr_disable(void); 22 | void register_handler(uint8_t vec_no, intr_handler handler); 23 | 24 | # endif 25 | -------------------------------------------------------------------------------- /chapter9/thread_schedule/kernel/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_IO_H 2 | # define _LIB_IO_H 3 | 4 | # include "stdint.h" 5 | 6 | /** 7 | * 向指定的端口写入一个字节的数据. 8 | */ 9 | static inline void outb(uint16_t port, uint8_t data) { 10 | asm volatile ("outb %b0, %w1" : : "a" (data), "Nd" (port)); 11 | } 12 | 13 | /** 14 | * 将addr起始处的word_cnt个字节写入端口port. 15 | */ 16 | static inline void outsw(uint16_t port, const void* addr, uint32_t word_cnt) { 17 | asm volatile ("cld; rep outsw" : "+S" (addr), "+c" (word_cnt) : "d" (port)); 18 | } 19 | 20 | /** 21 | * 将从端口port读入的一个字节返回. 22 | */ 23 | static inline uint8_t inb(uint16_t port) { 24 | uint8_t data; 25 | asm volatile ("inb %w1, %b0" : "=a" (data) : "Nd" (port)); 26 | return data; 27 | } 28 | 29 | /** 30 | * 将从port读取的word_cnt字节写入addr. 31 | */ 32 | static inline void insw(uint16_t port, void* addr, uint32_t word_cnt) { 33 | asm volatile ("cld; rep insw" : "+D" (addr), "+c" (word_cnt) : "d" (port) : "memory"); 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /chapter9/thread_schedule/kernel/kernel.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ; 对于CPU会自动压入错误码的中断类型,无需额外的操作 4 | %define ERROR_CODE nop 5 | ; 如果CPU没有压入错误码,为了保持处理逻辑的一致性,我们需要手动压入一个0 6 | %define ZERO push 0 7 | 8 | extern put_str 9 | ; 中断处理函数数组 10 | extern idt_table 11 | 12 | section .data 13 | intr_str db "interrupt occur!", 0xa, 0 14 | global intr_entry_table 15 | intr_entry_table: 16 | 17 | ; 中断处理程序宏定义 18 | %macro VECTOR 2 19 | section .text 20 | intr%1entry: 21 | 22 | %2 23 | ; 保存上下文 24 | push ds 25 | push es 26 | push fs 27 | push gs 28 | pushad 29 | 30 | mov al, 0x20 31 | out 0xa0, al 32 | out 0x20, al 33 | 34 | push %1 35 | 36 | ; 调用C的中断处理函数 37 | call [idt_table + 4 * %1] 38 | jmp intr_exit 39 | 40 | section .data 41 | dd intr%1entry 42 | 43 | %endmacro 44 | 45 | section .text 46 | global intr_exit 47 | intr_exit: 48 | add esp, 4 49 | popad 50 | pop gs 51 | pop fs 52 | pop es 53 | pop ds 54 | add esp, 4 55 | iretd 56 | 57 | VECTOR 0x00, ZERO 58 | VECTOR 0x01, ZERO 59 | VECTOR 0x02, ZERO 60 | VECTOR 0x03, ZERO 61 | VECTOR 0x04, ZERO 62 | VECTOR 0x05, ZERO 63 | VECTOR 0x06, ZERO 64 | VECTOR 0x07, ZERO 65 | VECTOR 0x08, ZERO 66 | VECTOR 0x09, ZERO 67 | VECTOR 0x0a, ZERO 68 | VECTOR 0x0b, ZERO 69 | VECTOR 0x0c, ZERO 70 | VECTOR 0x0d, ZERO 71 | VECTOR 0x0e, ZERO 72 | VECTOR 0x0f, ZERO 73 | VECTOR 0x10, ZERO 74 | VECTOR 0x11, ZERO 75 | VECTOR 0x12, ZERO 76 | VECTOR 0x13, ZERO 77 | VECTOR 0x14, ZERO 78 | VECTOR 0x15, ZERO 79 | VECTOR 0x16, ZERO 80 | VECTOR 0x17, ZERO 81 | VECTOR 0x18, ZERO 82 | VECTOR 0x19, ZERO 83 | VECTOR 0x1a, ZERO 84 | VECTOR 0x1b, ZERO 85 | VECTOR 0x1c, ZERO 86 | VECTOR 0x1d, ZERO 87 | VECTOR 0x1e, ERROR_CODE 88 | VECTOR 0x1f, ZERO 89 | VECTOR 0x20, ZERO -------------------------------------------------------------------------------- /chapter9/thread_schedule/kernel/main.c: -------------------------------------------------------------------------------- 1 | # include "kernel/print.h" 2 | # include "init.h" 3 | # include "thread.h" 4 | # include "interrupt.h" 5 | 6 | void k_thread_function_a(void*); 7 | void k_thread_function_b(void*); 8 | 9 | int main(void) { 10 | put_str("I am kernel.\n"); 11 | init_all(); 12 | 13 | thread_start("k_thread_a", 31, k_thread_function_a, "threadA "); 14 | thread_start("k_thread_b", 8, k_thread_function_b, "threadB "); 15 | 16 | intr_enable(); 17 | 18 | while (1) { 19 | put_str("main "); 20 | } 21 | 22 | return 0; 23 | } 24 | 25 | void k_thread_function_a(void* args) { 26 | // 这里必须是死循环,否则执行流并不会返回到main函数,所以CPU将会放飞自我,出发6号未知操作码异常 27 | while (1) { 28 | put_str((char*) args); 29 | } 30 | } 31 | 32 | void k_thread_function_b(void* args) { 33 | while (1) { 34 | put_str((char*) args); 35 | } 36 | } -------------------------------------------------------------------------------- /chapter9/thread_schedule/kernel/memory.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_MEMORY_H 2 | # define _KERNEL_MEMORY_H 3 | 4 | # include "stdint.h" 5 | # include "bitmap.h" 6 | 7 | // 存在标志 8 | # define PG_P_1 1 9 | # define PG_P_0 0 10 | // 只读 11 | # define PG_RW_R 0 12 | // 可写 13 | # define PG_RW_W 2 14 | // 系统级 15 | # define PG_US_S 0 16 | # define PG_US_U 4 17 | 18 | /** 19 | * 内存池类型标志. 20 | */ 21 | enum pool_flags { 22 | // 内核类型 23 | PF_KERNEL = 1, 24 | PF_USER = 2 25 | }; 26 | 27 | struct virtual_addr { 28 | struct bitmap vaddr_bitmap; 29 | // 虚拟内存的起始地址 30 | uint32_t vaddr_start; 31 | }; 32 | 33 | extern struct pool kernel_pool, user_pool; 34 | 35 | void mem_init(void); 36 | 37 | void* get_kernel_pages(uint32_t page_count); 38 | 39 | void* malloc_page(enum pool_flags pf, uint32_t page_count); 40 | 41 | # endif -------------------------------------------------------------------------------- /chapter9/thread_schedule/kernel/switch.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | section .text 3 | global switch_to 4 | switch_to: 5 | ; 将中断处理函数的上下文保存到目标PCB的栈中 6 | ; 这里隐含的是下次调度返回的地址其实是switch_to的返回地址 7 | push esi 8 | push edi 9 | push ebx 10 | push ebp 11 | mov eax, [esp + 20] 12 | mov [eax], esp 13 | 14 | ; 跳到目标PCB执行 15 | mov eax, [esp + 24] 16 | mov esp, [eax] 17 | pop ebp 18 | pop ebx 19 | pop edi 20 | pop esi 21 | ret -------------------------------------------------------------------------------- /chapter9/thread_schedule/kernel/thread.h: -------------------------------------------------------------------------------- 1 | # ifndef _THREAD_H 2 | # define _THREAD_H 3 | 4 | # include "stdint.h" 5 | # include "kernel/list.h" 6 | 7 | /** 8 | * 自定义通用函数类型. 9 | */ 10 | typedef void thread_func(void*); 11 | 12 | /** 13 | * 线程状态. 14 | */ 15 | enum task_status { 16 | TASK_RUNNING, 17 | TASK_READY, 18 | TASK_BLOCKED, 19 | TASK_WAITTING, 20 | TASK_HANGING, 21 | TASK_DIED 22 | }; 23 | 24 | /** 25 | * 中断栈. 26 | */ 27 | struct intr_stack { 28 | uint32_t vec_no; 29 | uint32_t edi; 30 | uint32_t esi; 31 | uint32_t ebp; 32 | uint32_t esp_dummy; 33 | uint32_t ebx; 34 | uint32_t edx; 35 | uint32_t ecx; 36 | uint32_t eax; 37 | uint32_t gs; 38 | uint32_t fs; 39 | uint32_t es; 40 | uint32_t ds; 41 | 42 | // 下面的属性由CPU从低特权级进入高特权级时压入 43 | uint32_t err_code; 44 | void (*eip) (void); 45 | uint32_t cs; 46 | uint32_t eflags; 47 | void* esp; 48 | uint32_t ss; 49 | }; 50 | 51 | struct thread_stack { 52 | uint32_t ebp; 53 | uint32_t ebx; 54 | uint32_t edi; 55 | uint32_t esi; 56 | 57 | // 第一次执行时指向待调用的函数kernel_thread,其它时候指向switch_to的返回地址. 58 | void (*eip) (thread_func* func, void* func_args); 59 | 60 | void (*unused_retaddr); 61 | thread_func* function; 62 | void* func_args; 63 | }; 64 | 65 | /** 66 | * PCB,进程或线程的控制块. 67 | */ 68 | struct task_struct { 69 | // 内核栈 70 | uint32_t* self_kstack; 71 | enum task_status status; 72 | char name[16]; 73 | uint8_t priority; 74 | // 当前线程可以占用的CPU嘀嗒数 75 | uint8_t ticks; 76 | // 此任务占用的总嘀嗒数 77 | uint32_t elaspsed_ticks; 78 | // 可执行队列节点 79 | struct list_elem general_tag; 80 | // 所有不可运行线程队列节点 81 | struct list_elem all_list_tag; 82 | uint32_t* pgdir; 83 | uint32_t stack_magic; 84 | }; 85 | 86 | struct task_struct* running_thread(); 87 | void thread_create(struct task_struct* pthread, thread_func function, void* func_args); 88 | void init_thread(struct task_struct* pthread, char* name, int prio); 89 | struct task_struct* thread_start(char* name, int prio, thread_func function, void* func_args); 90 | void schedule(); 91 | void thread_init(); 92 | 93 | # endif -------------------------------------------------------------------------------- /chapter9/thread_schedule/lib/bitmap.c: -------------------------------------------------------------------------------- 1 | # include "bitmap.h" 2 | # include "stdint.h" 3 | # include "string.h" 4 | # include "kernel/print.h" 5 | # include "interrupt.h" 6 | # include "debug.h" 7 | 8 | void bitmap_init(struct bitmap* btmap) { 9 | memset(btmap->bits, 0, btmap->btmp_bytes_len); 10 | } 11 | 12 | /** 13 | * 检测指定位是否为1,如果是,返回1. 14 | */ 15 | int bitmap_scan_test(struct bitmap* btmap, uint32_t index) { 16 | uint32_t byte_index = (index / 8); 17 | uint32_t bit_odd = byte_index % 8; 18 | 19 | return (btmap->bits[byte_index] & BITMAP_MASK << bit_odd); 20 | } 21 | 22 | /** 23 | * 在位图中申请连续的cnt个位. 24 | */ 25 | int bitmap_scan(struct bitmap* btmap, uint32_t cnt) { 26 | uint32_t idx_byte = 0; 27 | 28 | // 以字节为单位进行查找 29 | while ((0xff == btmap->bits[idx_byte]) && idx_byte < btmap->btmp_bytes_len) { 30 | ++idx_byte; 31 | } 32 | 33 | // 没有找到 34 | if (idx_byte == btmap->btmp_bytes_len) { 35 | return -1; 36 | } 37 | 38 | // 找到了一个字节不全为1,那么在字节内部再次进行查找具体的起使位 39 | int idx_bit = 0; 40 | while ((uint8_t) BITMAP_MASK << idx_bit & btmap->bits[idx_byte]) { 41 | ++idx_bit; 42 | } 43 | 44 | // 起始位 45 | int bit_idx_start = (idx_byte * 8 + idx_bit); 46 | if (cnt == 1) { 47 | return bit_idx_start; 48 | } 49 | 50 | uint32_t bit_left = (btmap->btmp_bytes_len * 8 - bit_idx_start); 51 | uint32_t count = 1; 52 | 53 | uint32_t next_bit = bit_idx_start + 1; 54 | 55 | bit_idx_start = -1; 56 | while (bit_left-- > 0) { 57 | if (!(bitmap_scan_test(btmap, next_bit))) { 58 | ++count; 59 | } else { 60 | count = 0; 61 | } 62 | 63 | if (count == cnt) { 64 | bit_idx_start = (next_bit - cnt + 1); 65 | break; 66 | } 67 | 68 | next_bit++; 69 | } 70 | 71 | return bit_idx_start; 72 | } 73 | 74 | void bitmap_set(struct bitmap* btmap, uint32_t index, int8_t value) { 75 | ASSERT(value == 0 || value == 1); 76 | 77 | uint32_t byte_index = index / 8; 78 | uint32_t bit_odd = index % 8; 79 | 80 | if (value) { 81 | btmap->bits[byte_index] |= (BITMAP_MASK << bit_odd); 82 | } else { 83 | btmap->bits[byte_index] &= ~(BITMAP_MASK << bit_odd); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /chapter9/thread_schedule/lib/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_KERNEL_BITMAP_H 2 | #define _LIB_KERNEL_BITMAP_H 3 | 4 | # include "global.h" 5 | 6 | # define BITMAP_MASK 1 7 | 8 | struct bitmap { 9 | uint32_t btmp_bytes_len; 10 | uint8_t* bits; 11 | }; 12 | 13 | void bitmap_init(struct bitmap* btmap); 14 | 15 | int bitmap_scan_test(struct bitmap* btmap, uint32_t bit_idx); 16 | 17 | int bitmap_scan(struct bitmap* btmap, uint32_t cnt); 18 | 19 | void bitmap_set(struct bitmap* btmap, uint32_t index, int8_t value); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /chapter9/thread_schedule/lib/kernel/list.h: -------------------------------------------------------------------------------- 1 | # ifndef _LIB_KERNEL_LIST_H 2 | # define _LIB_KERNEL_LIST_H 3 | 4 | # include "global.h" 5 | 6 | /** 7 | * 获取结构体内成员在结构体的偏移. 8 | */ 9 | # define offset(struct_type, member) (int) (&((struct_type*)0)->member) 10 | 11 | # define elem2entry(struct_type, struct_member_name, elem_ptr) \ 12 | (struct_type*) ((int) elem_ptr - offset(struct_type, struct_member_name)) 13 | 14 | /** 15 | * 链表节点. 16 | */ 17 | struct list_elem { 18 | struct list_elem* prev; 19 | struct list_elem* next; 20 | }; 21 | 22 | /** 23 | * 链表结构. 24 | */ 25 | struct list { 26 | struct list_elem head; 27 | struct list_elem tail; 28 | }; 29 | 30 | /** 31 | * 用于链表遍历的回调函数. 32 | */ 33 | typedef int (function) (struct list_elem*, int arg); 34 | 35 | void list_init(struct list* list); 36 | void list_insert_before(struct list_elem* before, struct list_elem* elem); 37 | void list_push(struct list* list, struct list_elem* elem); 38 | void list_append(struct list* list, struct list_elem* elem); 39 | void list_remove(struct list_elem* elem); 40 | struct list_elem* list_pop(struct list* list); 41 | int list_find(struct list* list, struct list_elem* elem); 42 | int list_empty(struct list* list); 43 | uint32_t list_length(struct list* list); 44 | struct list_elem* list_traversal(struct list* list, function func, int arg); 45 | 46 | # endif -------------------------------------------------------------------------------- /chapter9/thread_schedule/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 为print.asm提供方便引用的头文件定义. 3 | */ 4 | # ifndef _LIB_KERNEL_PRINT_H 5 | # define _LIB_KERNEL_PRINT_H 6 | 7 | # include "stdint.h" 8 | 9 | void put_char(uint8_t char_asci); 10 | 11 | /** 12 | * 字符串打印,必须以\0结尾. 13 | */ 14 | void put_str(char* message); 15 | 16 | /** 17 | * 以16进制的形式打印数字. 18 | */ 19 | void put_int(uint32_t num); 20 | 21 | void set_cursor(uint32_t pos); 22 | 23 | # endif -------------------------------------------------------------------------------- /chapter9/thread_schedule/lib/stdint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 仿照/usr/include/stdint.h定义我们自己的数据类型. 3 | */ 4 | #ifndef _LIB_STDINT_H 5 | #define _LIB_STDINT_H 6 | 7 | typedef signed char int8_t; 8 | typedef signed short int int16_t; 9 | typedef signed int int32_t; 10 | typedef signed long long int int64_t; 11 | 12 | typedef unsigned char uint8_t; 13 | typedef unsigned short int uint16_t; 14 | typedef unsigned int uint32_t; 15 | typedef unsigned long long int uint64_t; 16 | 17 | #endif -------------------------------------------------------------------------------- /chapter9/thread_schedule/lib/string.h: -------------------------------------------------------------------------------- 1 | # ifndef _LIB_STRING_H 2 | # define _LIB_STRING_H 3 | 4 | # include "global.h" 5 | # include "debug.h" 6 | 7 | void memset(void* address, uint8_t value, uint32_t size); 8 | void memcpy(void* dst, const void* src, uint32_t size); 9 | int memcmp(const void* left, const void* right, uint32_t size); 10 | char* strcpy(char* dst, const char* src); 11 | uint32_t strlen(const char* str); 12 | int8_t strcmp(const char* left, const char* right); 13 | char* strchr(const char* str, const uint8_t c); 14 | char* strrchr(const char* str, const uint8_t c); 15 | char* strcat(char* dst, const char* src); 16 | uint32_t strchrs(const char* str, const uint8_t c); 17 | 18 | # endif -------------------------------------------------------------------------------- /chapter9/thread_start/bochsrc.bxrc: -------------------------------------------------------------------------------- 1 | # Bochs配置文件 2 | 3 | # 机器内存: 32MB 4 | megs: 32 5 | 6 | # 启动方式 7 | boot: disk 8 | 9 | # 关闭鼠标 10 | mouse: enabled=0 11 | 12 | # 硬盘设置 13 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 14 | ata0-master: type=disk, path="disk.img", cylinders=20, heads=16, spt=63 15 | -------------------------------------------------------------------------------- /chapter9/thread_start/device/timer.c: -------------------------------------------------------------------------------- 1 | # include "io.h" 2 | # include "kernel/print.h" 3 | 4 | # define IRQ0_FREQUENCY 1000 5 | # define INPUT_FREQUENCY 1193180 6 | # define COUNTER0_VALUE INPUT_FREQUENCY / IRQ0_FREQUENCY 7 | # define COUNTER0_PORT 0x40 8 | # define COUNTER_MODE 2 9 | # define COUNTER0_NO 0 10 | # define READ_WRITE_LATCH 3 11 | # define PIT_CONTROL_PORT 0x43 12 | 13 | 14 | static void frequency_set(uint8_t counter_port, 15 | uint8_t counter_no, 16 | uint8_t rwl, 17 | uint8_t counter_mode, 18 | uint16_t counter_value) { 19 | outb(PIT_CONTROL_PORT, (uint8_t) (counter_no << 6 | rwl << 4 | counter_mode << 1)); 20 | outb(counter_port, (uint8_t) counter_value); 21 | outb(counter_port, (uint8_t) counter_value >> 8); 22 | } 23 | 24 | /** 25 | * 初始化PIT 8253. 26 | */ 27 | void timer_init() { 28 | put_str("timer_init start.\n"); 29 | frequency_set(COUNTER0_PORT, COUNTER0_NO, READ_WRITE_LATCH, COUNTER_MODE, COUNTER0_VALUE); 30 | put_str("timer_init done.\n"); 31 | } -------------------------------------------------------------------------------- /chapter9/thread_start/device/timer.h: -------------------------------------------------------------------------------- 1 | void timer_init(); -------------------------------------------------------------------------------- /chapter9/thread_start/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------loader和kernel------------- 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_START_SECTOR equ 0x9 6 | KERNEL_BIN_BASE_ADDR equ 0x70000 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ; gdt描述符属性 10 | ; 段描述符高23位,表示段界限的粒度为4KB 11 | DESC_G_4K equ 100000000000000000000000b 12 | 13 | ; D/B为,1表示运行在32位模式下 14 | DESC_D_32 equ 10000000000000000000000b 15 | ; 高21位,如果为1表示为64位代码段,目前我们都是在32位模式下操作,故为零 16 | DESC_L equ 0000000000000000000000b 17 | ; 没有明确的用途,取值随意 18 | DESC_AVL equ 000000000000000000000b 19 | ; 第二部分段界限值,由于采用了32位平坦模型,所以段界限为(4GB / 4KB) - 1 = 0xFFFFF,故为全1 20 | DESC_LIMIT_CODE2 equ 11110000000000000000b 21 | DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2 22 | ; 书中取全零,怀疑是错误的,因为保护模式的基地址是0xb8000,所以最后8位应该是b,而不是0 23 | DESC_LIMIT_VIDEO2 equ 00000000000000000000000000001011b 24 | DESC_P equ 1000000000000000b 25 | DESC_DPL_0 equ 000000000000000b 26 | DESC_DPL_1 equ 010000000000000b 27 | DESC_DPL_2 equ 100000000000000b 28 | DESC_DPL_3 equ 110000000000000b 29 | DESC_S_CODE equ 1000000000000b 30 | DESC_S_DATA equ DESC_S_CODE 31 | DESC_S_sys equ 0000000000000b 32 | DESC_TYPE_CODE equ 100000000000b 33 | DESC_TYPE_DATA equ 001000000000b 34 | 35 | ; 代码段描述符的高32位表示,其中(0x00 << 24表示最高8位的段基址值,由于我们采用的是平坦模型,故基址为零),后面唯一可变的就是段界限值 36 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 37 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 38 | DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00 39 | 40 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 41 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 42 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 43 | 44 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 45 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + \ 46 | DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 47 | 48 | ; 选择字属性 49 | RPL0 equ 00b 50 | RPL1 equ 01b 51 | RPL2 equ 10b 52 | RPL3 equ 11b 53 | TI_GDT equ 000b 54 | TI_LDT equ 100b 55 | 56 | ; 页表相关属性 57 | PG_P equ 1b 58 | PG_RW_R equ 00b 59 | PG_RW_W equ 10b 60 | PG_US_S equ 000b 61 | PG_US_U equ 100b 62 | 63 | PT_NULL equ 0 -------------------------------------------------------------------------------- /chapter9/thread_start/kernel/debug.c: -------------------------------------------------------------------------------- 1 | # include "debug.h" 2 | # include "kernel/print.h" 3 | # include "interrupt.h" 4 | 5 | void panic_spin(char* filename, int line, const char* func, const char* condition) { 6 | intr_disable(); 7 | 8 | put_str("Something wrong..."); 9 | 10 | put_str("FileName: "); 11 | put_str(filename); 12 | put_char('\n'); 13 | 14 | put_str("Line: "); 15 | put_int(line); 16 | put_char('\n'); 17 | 18 | put_str("Function: "); 19 | put_str(func); 20 | put_char('\n'); 21 | 22 | put_str("Condition: "); 23 | put_str(condition); 24 | put_char('\n'); 25 | 26 | while (1); 27 | } -------------------------------------------------------------------------------- /chapter9/thread_start/kernel/debug.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_DEBUG_H 2 | # define _KERNEL_DEBUG_H 3 | 4 | void panic_spin(char* filename, int line, const char* func, const char* condition); 5 | 6 | /** 7 | * 当断言被触发时调用. 8 | * _FILE_: 内置宏,表示调用的文件名 9 | * _LINE_: 内置宏,被编译文件的行号 10 | * _func_: 内置宏: 被编译的函数名 11 | * _VA_ARGS_: 函数调用参数 12 | */ 13 | # define PANIC(...) panic_spin (__FILE__, __LINE__, __func__, __VA_ARGS__) 14 | 15 | # ifdef NDEBUG 16 | # define ASSERT(CONDITION) ((void) 0) 17 | # else 18 | # define ASSERT(CONDITION) \ 19 | if (CONDITION) { \ 20 | } else { \ 21 | PANIC(#CONDITION); \ 22 | } 23 | # endif 24 | # endif -------------------------------------------------------------------------------- /chapter9/thread_start/kernel/global.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_GLOBAL_H 2 | #define _KERNEL_GLOBAL_H 3 | 4 | # include "stdint.h" 5 | 6 | # define RPL0 0 7 | # define RPL1 1 8 | # define RPL2 2 9 | # define RPL3 3 10 | 11 | # define TI_GDT 0 12 | # define TI_LDT 1 13 | 14 | # define SELECTOR_K_CODE ((1 << 3) + (TI_GDT << 2) + RPL0) 15 | # define SELECTOR_K_DATA ((2 << 3) + (TI_GDT << 2) + RPL0) 16 | # define SELECTOR_K_STACK SELECTOR_K_DATA 17 | # define SELECTOR_K_GS ((3 << 3) + (TI_GDT << 2) + RPL0) 18 | 19 | /* IDT描述符属性 */ 20 | # define IDT_DESC_P 1 21 | # define IDT_DESC_DPL0 0 22 | # define IDT_DESC_DPL3 3 23 | # define IDT_DESC_32_TYPE 0xE 24 | # define IDT_DESC_16_TYPE 0x6 25 | 26 | # define IDT_DESC_ATTR_DPL0 \ 27 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL0 << 5) + IDT_DESC_32_TYPE) 28 | 29 | # define IDT_DESC_ATTR_DPL3 \ 30 | ((IDT_DESC_P << 7) + (IDT_DESC_DPL3 << 5) + IDT_DESC_32_TYPE) 31 | 32 | # define NULL 0 33 | 34 | #endif -------------------------------------------------------------------------------- /chapter9/thread_start/kernel/init.c: -------------------------------------------------------------------------------- 1 | # include "init.h" 2 | # include "kernel/print.h" 3 | # include "timer.h" 4 | # include "memory.h" 5 | 6 | void init_all() { 7 | put_str("init_all.\n"); 8 | idt_init(); 9 | timer_init(); 10 | mem_init(); 11 | } -------------------------------------------------------------------------------- /chapter9/thread_start/kernel/init.h: -------------------------------------------------------------------------------- 1 | void init_all(void); -------------------------------------------------------------------------------- /chapter9/thread_start/kernel/interrupt.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_INTERRUPT_H 2 | # define _KERNEL_INTERRUPT_H 3 | 4 | # include "stdint.h" 5 | 6 | typedef void* intr_handler; 7 | 8 | void idt_init(void); 9 | 10 | /** 11 | * 中断状态. 12 | */ 13 | enum intr_status { 14 | INTR_OFF, 15 | INTR_ON 16 | }; 17 | 18 | enum intr_status intr_get_status(void); 19 | enum intr_status intr_set_status(enum intr_status); 20 | enum intr_status intr_enable(void); 21 | enum intr_status intr_disable(void); 22 | 23 | # endif 24 | -------------------------------------------------------------------------------- /chapter9/thread_start/kernel/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_IO_H 2 | # define _LIB_IO_H 3 | 4 | # include "stdint.h" 5 | 6 | /** 7 | * 向指定的端口写入一个字节的数据. 8 | */ 9 | static inline void outb(uint16_t port, uint8_t data) { 10 | asm volatile ("outb %b0, %w1" : : "a" (data), "Nd" (port)); 11 | } 12 | 13 | /** 14 | * 将addr起始处的word_cnt个字节写入端口port. 15 | */ 16 | static inline void outsw(uint16_t port, const void* addr, uint32_t word_cnt) { 17 | asm volatile ("cld; rep outsw" : "+S" (addr), "+c" (word_cnt) : "d" (port)); 18 | } 19 | 20 | /** 21 | * 将从端口port读入的一个字节返回. 22 | */ 23 | static inline uint8_t inb(uint16_t port) { 24 | uint8_t data; 25 | asm volatile ("inb %w1, %b0" : "=a" (data) : "Nd" (port)); 26 | return data; 27 | } 28 | 29 | /** 30 | * 将从port读取的word_cnt字节写入addr. 31 | */ 32 | static inline void insw(uint16_t port, void* addr, uint32_t word_cnt) { 33 | asm volatile ("cld; rep insw" : "+D" (addr), "+c" (word_cnt) : "d" (port) : "memory"); 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /chapter9/thread_start/kernel/kernel.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ; 对于CPU会自动压入错误码的中断类型,无需额外的操作 4 | %define ERROR_CODE nop 5 | ; 如果CPU没有压入错误码,为了保持处理逻辑的一致性,我们需要手动压入一个0 6 | %define ZERO push 0 7 | 8 | extern put_str 9 | ; 中断处理函数数组 10 | extern idt_table 11 | 12 | section .data 13 | intr_str db "interrupt occur!", 0xa, 0 14 | global intr_entry_table 15 | intr_entry_table: 16 | 17 | ; 中断处理程序宏定义 18 | %macro VECTOR 2 19 | section .text 20 | intr%1entry: 21 | 22 | %2 23 | ; 保存上下文 24 | push ds 25 | push es 26 | push fs 27 | push gs 28 | pushad 29 | 30 | mov al, 0x20 31 | out 0xa0, al 32 | out 0x20, al 33 | 34 | push %1 35 | 36 | ; 调用C的中断处理函数 37 | call [idt_table + 4 * %1] 38 | jmp intr_exit 39 | 40 | section .data 41 | dd intr%1entry 42 | 43 | %endmacro 44 | 45 | section .text 46 | global intr_exit 47 | intr_exit: 48 | add esp, 4 49 | popad 50 | pop gs 51 | pop fs 52 | pop es 53 | pop ds 54 | add esp, 4 55 | iretd 56 | 57 | VECTOR 0x00, ZERO 58 | VECTOR 0x01, ZERO 59 | VECTOR 0x02, ZERO 60 | VECTOR 0x03, ZERO 61 | VECTOR 0x04, ZERO 62 | VECTOR 0x05, ZERO 63 | VECTOR 0x06, ZERO 64 | VECTOR 0x07, ZERO 65 | VECTOR 0x08, ZERO 66 | VECTOR 0x09, ZERO 67 | VECTOR 0x0a, ZERO 68 | VECTOR 0x0b, ZERO 69 | VECTOR 0x0c, ZERO 70 | VECTOR 0x0d, ZERO 71 | VECTOR 0x0e, ZERO 72 | VECTOR 0x0f, ZERO 73 | VECTOR 0x10, ZERO 74 | VECTOR 0x11, ZERO 75 | VECTOR 0x12, ZERO 76 | VECTOR 0x13, ZERO 77 | VECTOR 0x14, ZERO 78 | VECTOR 0x15, ZERO 79 | VECTOR 0x16, ZERO 80 | VECTOR 0x17, ZERO 81 | VECTOR 0x18, ZERO 82 | VECTOR 0x19, ZERO 83 | VECTOR 0x1a, ZERO 84 | VECTOR 0x1b, ZERO 85 | VECTOR 0x1c, ZERO 86 | VECTOR 0x1d, ZERO 87 | VECTOR 0x1e, ERROR_CODE 88 | VECTOR 0x1f, ZERO 89 | VECTOR 0x20, ZERO -------------------------------------------------------------------------------- /chapter9/thread_start/kernel/main.c: -------------------------------------------------------------------------------- 1 | # include "kernel/print.h" 2 | # include "init.h" 3 | # include "thread.h" 4 | 5 | void k_thread_function(void*); 6 | 7 | int main(void) { 8 | put_str("I am kernel.\n"); 9 | init_all(); 10 | 11 | thread_start("k_thread_1", 31, k_thread_function, "skywalker "); 12 | 13 | while (1); 14 | return 0; 15 | } 16 | 17 | void k_thread_function(void* args) { 18 | // 这里必须是死循环,否则执行流并不会返回到main函数,所以CPU将会放飞自我,触发6号未知操作码异常 19 | while (1) { 20 | put_str((char*) args); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /chapter9/thread_start/kernel/memory.h: -------------------------------------------------------------------------------- 1 | # ifndef _KERNEL_MEMORY_H 2 | # define _KERNEL_MEMORY_H 3 | 4 | # include "stdint.h" 5 | # include "bitmap.h" 6 | 7 | // 存在标志 8 | # define PG_P_1 1 9 | # define PG_P_0 0 10 | // 只读 11 | # define PG_RW_R 0 12 | // 可写 13 | # define PG_RW_W 2 14 | // 系统级 15 | # define PG_US_S 0 16 | # define PG_US_U 4 17 | 18 | /** 19 | * 内存池类型标志. 20 | */ 21 | enum pool_flags { 22 | // 内核类型 23 | PF_KERNEL = 1, 24 | PF_USER = 2 25 | }; 26 | 27 | struct virtual_addr { 28 | struct bitmap vaddr_bitmap; 29 | // 虚拟内存的起始地址 30 | uint32_t vaddr_start; 31 | }; 32 | 33 | extern struct pool kernel_pool, user_pool; 34 | 35 | void mem_init(void); 36 | 37 | void* get_kernel_pages(uint32_t page_count); 38 | 39 | void* malloc_page(enum pool_flags pf, uint32_t page_count); 40 | 41 | # endif -------------------------------------------------------------------------------- /chapter9/thread_start/kernel/thread.c: -------------------------------------------------------------------------------- 1 | # include "thread.h" 2 | # include "stdint.h" 3 | # include "string.h" 4 | # include "global.h" 5 | # include "memory.h" 6 | 7 | # define PAGE_SIZE 4096 8 | 9 | static void kernel_thread(thread_func* function, void* func_args); 10 | 11 | static void kernel_thread(thread_func* function, void* func_args) { 12 | function(func_args); 13 | } 14 | 15 | /** 16 | * 初始化线程栈. 17 | */ 18 | void thread_create(struct task_struct* pthread, thread_func function, void* func_args) { 19 | pthread->self_kstack -= sizeof(struct intr_stack); 20 | pthread->self_kstack -= sizeof(struct thread_stack); 21 | 22 | struct thread_stack* kthread_stack = (struct thread_stack*) pthread->self_kstack; 23 | kthread_stack->eip = kernel_thread; 24 | kthread_stack->function = function; 25 | kthread_stack->func_args = func_args; 26 | kthread_stack->ebp = kthread_stack->ebx = kthread_stack->edi = kthread_stack->esi = 0; 27 | } 28 | 29 | /** 30 | * 初始化线程基本信息. 31 | */ 32 | void init_thread(struct task_struct* pthread, char* name, int prio) { 33 | memset(pthread, 0, sizeof(*pthread)); 34 | strcpy(pthread->name, name); 35 | pthread->status = TASK_RUNNING; 36 | pthread->priority = prio; 37 | // PCB所在物理页的顶端地址 38 | pthread->self_kstack = (uint32_t*) ((uint32_t) pthread + PAGE_SIZE); 39 | pthread->stack_magic = 0x77777777; 40 | } 41 | 42 | /** 43 | * 创建线程. 44 | */ 45 | struct task_struct* thread_start(char* name, int prio, thread_func function, void* func_args) { 46 | struct task_struct* thread = get_kernel_pages(1); 47 | 48 | init_thread(thread, name, prio); 49 | thread_create(thread, function, func_args); 50 | 51 | asm volatile ("movl %0, %%esp; pop %%ebp; pop %%ebx; pop %%edi; pop %%esi; ret" : : "g" (thread->self_kstack) : "memory"); 52 | return thread; 53 | } -------------------------------------------------------------------------------- /chapter9/thread_start/kernel/thread.h: -------------------------------------------------------------------------------- 1 | # ifndef _THREAD_H 2 | # define _THREAD_H 3 | 4 | # include "stdint.h" 5 | 6 | /** 7 | * 自定义通用函数类型. 8 | */ 9 | typedef void thread_func(void*); 10 | 11 | /** 12 | * 线程状态. 13 | */ 14 | enum task_status { 15 | TASK_RUNNING, 16 | TASK_READY, 17 | TASK_BLOCKED, 18 | TASK_WAITTING, 19 | TASK_HANGING, 20 | TASK_DIED 21 | }; 22 | 23 | /** 24 | * 中断栈. 25 | */ 26 | struct intr_stack { 27 | uint32_t vec_no; 28 | uint32_t edi; 29 | uint32_t esi; 30 | uint32_t ebp; 31 | uint32_t esp_dummy; 32 | uint32_t ebx; 33 | uint32_t edx; 34 | uint32_t ecx; 35 | uint32_t eax; 36 | uint32_t gs; 37 | uint32_t fs; 38 | uint32_t es; 39 | uint32_t ds; 40 | 41 | // 下面的属性由CPU从低特权级进入高特权级时压入 42 | uint32_t err_code; 43 | void (*eip) (void); 44 | uint32_t cs; 45 | uint32_t eflags; 46 | void* esp; 47 | uint32_t ss; 48 | }; 49 | 50 | struct thread_stack { 51 | uint32_t ebp; 52 | uint32_t ebx; 53 | uint32_t edi; 54 | uint32_t esi; 55 | 56 | // 第一次执行时指向待调用的函数kernel_thread,其它时候指向switch_to的返回地址. 57 | void (*eip) (thread_func* func, void* func_args); 58 | 59 | void (*unused_retaddr); 60 | thread_func* function; 61 | void* func_args; 62 | }; 63 | 64 | /** 65 | * PCB,进程或线程的控制块. 66 | */ 67 | struct task_struct { 68 | // 内核栈 69 | uint32_t* self_kstack; 70 | enum task_status status; 71 | uint8_t priority; 72 | char name[16]; 73 | uint32_t stack_magic; 74 | }; 75 | 76 | void thread_create(struct task_struct* pthread, thread_func function, void* func_args); 77 | void init_thread(struct task_struct* pthread, char* name, int prio); 78 | struct task_struct* thread_start(char* name, int prio, thread_func function, void* func_args); 79 | 80 | # endif -------------------------------------------------------------------------------- /chapter9/thread_start/lib/bitmap.c: -------------------------------------------------------------------------------- 1 | # include "bitmap.h" 2 | # include "stdint.h" 3 | # include "string.h" 4 | # include "kernel/print.h" 5 | # include "interrupt.h" 6 | # include "debug.h" 7 | 8 | void bitmap_init(struct bitmap* btmap) { 9 | memset(btmap->bits, 0, btmap->btmp_bytes_len); 10 | } 11 | 12 | /** 13 | * 检测指定位是否为1,如果是,返回1. 14 | */ 15 | int bitmap_scan_test(struct bitmap* btmap, uint32_t index) { 16 | uint32_t byte_index = (index / 8); 17 | uint32_t bit_odd = byte_index % 8; 18 | 19 | return (btmap->bits[byte_index] & BITMAP_MASK << bit_odd); 20 | } 21 | 22 | /** 23 | * 在位图中申请连续的cnt个位. 24 | */ 25 | int bitmap_scan(struct bitmap* btmap, uint32_t cnt) { 26 | uint32_t idx_byte = 0; 27 | 28 | // 以字节为单位进行查找 29 | while ((0xff == btmap->bits[idx_byte]) && idx_byte < btmap->btmp_bytes_len) { 30 | ++idx_byte; 31 | } 32 | 33 | // 没有找到 34 | if (idx_byte == btmap->btmp_bytes_len) { 35 | return -1; 36 | } 37 | 38 | // 找到了一个字节不全为1,那么在字节内部再次进行查找具体的起使位 39 | int idx_bit = 0; 40 | while ((uint8_t) BITMAP_MASK << idx_bit & btmap->bits[idx_byte]) { 41 | ++idx_bit; 42 | } 43 | 44 | // 起始位 45 | int bit_idx_start = (idx_byte * 8 + idx_bit); 46 | if (cnt == 1) { 47 | return bit_idx_start; 48 | } 49 | 50 | uint32_t bit_left = (btmap->btmp_bytes_len * 8 - bit_idx_start); 51 | uint32_t count = 1; 52 | 53 | uint32_t next_bit = bit_idx_start + 1; 54 | 55 | bit_idx_start = -1; 56 | while (bit_left-- > 0) { 57 | if (!(bitmap_scan_test(btmap, next_bit))) { 58 | ++count; 59 | } else { 60 | count = 0; 61 | } 62 | 63 | if (count == cnt) { 64 | bit_idx_start = (next_bit - cnt + 1); 65 | break; 66 | } 67 | 68 | next_bit++; 69 | } 70 | 71 | return bit_idx_start; 72 | } 73 | 74 | void bitmap_set(struct bitmap* btmap, uint32_t index, int8_t value) { 75 | ASSERT(value == 0 || value == 1); 76 | 77 | uint32_t byte_index = index / 8; 78 | uint32_t bit_odd = index % 8; 79 | 80 | if (value) { 81 | btmap->bits[byte_index] |= (BITMAP_MASK << bit_odd); 82 | } else { 83 | btmap->bits[byte_index] &= ~(BITMAP_MASK << bit_odd); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /chapter9/thread_start/lib/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_KERNEL_BITMAP_H 2 | #define _LIB_KERNEL_BITMAP_H 3 | 4 | # include "global.h" 5 | 6 | # define BITMAP_MASK 1 7 | 8 | struct bitmap { 9 | uint32_t btmp_bytes_len; 10 | uint8_t* bits; 11 | }; 12 | 13 | void bitmap_init(struct bitmap* btmap); 14 | 15 | int bitmap_scan_test(struct bitmap* btmap, uint32_t bit_idx); 16 | 17 | int bitmap_scan(struct bitmap* btmap, uint32_t cnt); 18 | 19 | void bitmap_set(struct bitmap* btmap, uint32_t index, int8_t value); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /chapter9/thread_start/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 为print.asm提供方便引用的头文件定义. 3 | */ 4 | #ifndef _LIB_KERNEL_PRINT_H 5 | #define _LIB_KERNEL_PRINT_H 6 | 7 | # include "stdint.h" 8 | 9 | void put_char(uint8_t char_asci); 10 | 11 | /** 12 | * 字符串打印,必须以\0结尾. 13 | */ 14 | void put_str(char* message); 15 | 16 | /** 17 | * 以16进制的形式打印数字. 18 | */ 19 | void put_int(uint32_t num); 20 | 21 | #endif -------------------------------------------------------------------------------- /chapter9/thread_start/lib/stdint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 仿照/usr/include/stdint.h定义我们自己的数据类型. 3 | */ 4 | #ifndef _LIB_STDINT_H 5 | #define _LIB_STDINT_H 6 | 7 | typedef signed char int8_t; 8 | typedef signed short int int16_t; 9 | typedef signed int int32_t; 10 | typedef signed long long int int64_t; 11 | 12 | typedef unsigned char uint8_t; 13 | typedef unsigned short int uint16_t; 14 | typedef unsigned int uint32_t; 15 | typedef unsigned long long int uint64_t; 16 | 17 | #endif -------------------------------------------------------------------------------- /chapter9/thread_start/lib/string.h: -------------------------------------------------------------------------------- 1 | # ifndef _LIB_STRING_H 2 | # define _LIB_STRING_H 3 | 4 | # include "global.h" 5 | # include "debug.h" 6 | 7 | void memset(void* address, uint8_t value, uint32_t size); 8 | void memcpy(void* dst, const void* src, uint32_t size); 9 | int memcmp(const void* left, const void* right, uint32_t size); 10 | char* strcpy(char* dst, const char* src); 11 | uint32_t strlen(const char* str); 12 | int8_t strcmp(const char* left, const char* right); 13 | char* strchr(const char* str, const uint8_t c); 14 | char* strrchr(const char* str, const uint8_t c); 15 | char* strcat(char* dst, const char* src); 16 | uint32_t strchrs(const char* str, const uint8_t c); 17 | 18 | # endif -------------------------------------------------------------------------------- /images/chapter_10_with_lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_10_with_lock.png -------------------------------------------------------------------------------- /images/chapter_3_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_3_result.png -------------------------------------------------------------------------------- /images/chapter_4_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_4_result.png -------------------------------------------------------------------------------- /images/chapter_5_detect_memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_5_detect_memory.png -------------------------------------------------------------------------------- /images/chapter_5_memory_size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_5_memory_size.png -------------------------------------------------------------------------------- /images/chapter_5_page_memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_5_page_memory.png -------------------------------------------------------------------------------- /images/chapter_6_put_int.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_6_put_int.png -------------------------------------------------------------------------------- /images/chapter_6_put_str.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_6_put_str.png -------------------------------------------------------------------------------- /images/chapter_7_improve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_7_improve.png -------------------------------------------------------------------------------- /images/chapter_7_timer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_7_timer.png -------------------------------------------------------------------------------- /images/chapter_7_with_asm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_7_with_asm.png -------------------------------------------------------------------------------- /images/chapter_8_assert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_8_assert.png -------------------------------------------------------------------------------- /images/chapter_8_malloc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_8_malloc.png -------------------------------------------------------------------------------- /images/chapter_8_memory_pool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_8_memory_pool.png -------------------------------------------------------------------------------- /images/chapter_9_thread_schedule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_9_thread_schedule.png -------------------------------------------------------------------------------- /images/chapter_9_thread_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/chapter_9_thread_start.png -------------------------------------------------------------------------------- /images/thread_schedule_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaswalker/tiny-os/e53c59f358be3dbe0082ac2a0addba2f2cecd90c/images/thread_schedule_graph.png --------------------------------------------------------------------------------