📄 setup.asm
字号:
;调用:ah=eh; al=要写的字符;--------------------------------------------------------print_msg: push ax mov ah, 0ehdisp_next_ch: lodsb ; `LODSB' loads a byte from `[DS:SI]' or `[DS:ESI]' into `AL' cmp al, 0 jz quit int 10h ; 利用BIOS int 10h中断ah=0eh功能进行打印字符 jmp disp_next_chquit: pop ax ret;--------------------------------------------------------;清屏;调用:ah=7; al=向下滚动的行数; bh=空白顶行所使用的属性; ch=滚动的顶行; cl=滚动的左边列; dh=滚动的底行; dl=滚动的右边列;--------------------------------------------------------cls: mov ax, 0x0700 mov bh, 0x07 ; mov cx, 0x0000 mov dx, 0x174f ; 利用BIOS int 10h中断ah=07h功能进行清屏 int 0x10 ret ;-------------------------------------------------------- ; read_kernel_to_memory : 读指定的扇区到内存中 ; Input parameters: ; es:bx = 待写的内存地址; ch = 磁道号 ; cl = 开始的扇区号; dh = 磁头号; dl = 驱动器号; [kernel_sectors] = 待读的扇区数;-------------------------------------------------------- read_kernel_to_memory:readon: call read_one_sector ; 每个磁道有512*18=9k字节 dec word [kernel_sectors] ; 每读一个扇区后,待读内核扇区数减一,读到0为止 jz read_kernel_ok ; 读取内核完成 cmp bx, 0 je got_64k ; 完成64k读写后,下移64k进行写next_sector: cmp cl, SECTOR_SPER_TRACK - 1 ; 是否是磁道的最后一个扇区 ja read_next_track ; 如果读到最后一个扇区,就开始读下一个磁道 inc cl ; 设置读取第cl个扇区 jmp readon ; 又开始读扇区got_64k: push ax mov ax, es add ax, 0x1000 ; 设置ES为下个64k的边界 mov es, ax pop ax jmp next_sector read_next_track: mov cl, 1 inc dh ; 下一个磁头 and dh, 0x01 cmp dh, 0 jnz same_track ; 如果磁头号为奇数,则读同一磁道第1磁头 inc ch ; 跳到下个磁道same_track: jmp readon read_kernel_ok: ret ;读内核完成read_one_sector: mov ax, 0x0201 ;mov ah, 2 ; 利用BIOS int 13h的功能2读取磁盘 ;mov al, 1 ; 每次读取一个扇区 ;mov dl, [boot_drv] call read_data_from_floppy call print_dot ; add bx, 512 ; 读内核的内存指针往后移动512字节,每一扇区为512字节,当读完64k后,bx会溢出恢复为0 ret;------------------------------------------------------- ; 打印'.'(0x2e):;------------------------------------------------------- print_dot: push ax mov ax, 0x0e2e int 0x10 pop ax ret ;------------------------------------------------------- ; read_data_from_floppy: ; 从软驱中读取,如果出错则重试3次,超过3次则死机ayed. ;-------------------------------------------------------read_data_from_floppy: push ax push bx push cx push dx int 0x13 ; 读取 jnc read_ok xor ax, ax xor dx, dx int 0x13 ; 如果读失败,则软驱重启 dec byte [retries] jz .load_error ; 死机 pop dx pop cx pop bx pop ax jmp read_data_from_floppy.load_error mov si, err_msg call print_msg jmp $ ; 打印出错信息后死机read_ok: mov byte [retries], 3 ; 恢复重试次数 pop dx pop cx pop bx add sp, 2 ; 保存ax ret ;--------------------------------------------------------------------------- [BITS 32]go_pm: mov ax, KERNEL_DS mov ds, ax mov es, ax mov ss, ax mov fs, ax mov gs, ax ; 重新设置段寄存器 mov esp, 0x9FFFF ; 重新初始化堆栈指针;移动内核到1M处move_kernel_high_mem: mov edi, 0x100000 mov esi, 0x10000 mov ecx, 512 * 1024 rep movsb;清空原先存放内核的内存 mov cx, 0 ; mov ebx, PAGE_DIR ;clear_page_table: mov dword [ebx], 0 ; add ebx, 4 ; inc cx; cmp cx, 10240 ; jne clear_page_table ; ;在0x10000处建立页目录,16M;PAGE_OFFSET >> 20得到一个page_dir_entry, 这个20最好注释一下, ;PAGE_OFFSET >> 22得到page dir index, 然后在乘以4, 所以右移20位,而不是22位 mov cx, 0 ; mov ebx, PAGE_DIR + (PAGE_OFFSET >> 20) ; mov eax, PAGE_0_ADDR + 7;create_page_table: mov dword [ebx], eax ; add eax, PAGE_SIZE ; add ebx, 4 ; inc cx; cmp cx, [PARAM_ADDR + 2] ; jne create_page_table ; ;建立线性地址与物理地址相同的页目录,一定要建立,;不然当开启分页时后马上就会出错,;等进入start_kernel之后就要取消此页映射;不然如果有编码错误,且落在低地址区,就麻烦了!!!;这里只映射0--4M mov cx, 0 ; mov ebx, PAGE_DIR ; mov eax, PAGE_0_ADDR + 7 ; mov dword [ebx], eax ; ;建立页表 mov edi, PAGE_3_ADDR + 4092 ; mov eax, 0x00fff007 stdl1: stosd sub eax, 0x1000 jge l1 ;准备开启分页 ;设置页目录地址 mov eax, PAGE_DIR mov cr3, eax ;开启分页 mov eax, cr0 or eax, 0x80000000 mov cr0, eax lgdt [gdtr] ; 完成分页之后,还需得加载GDT,因为内核在0xC0000000处 mov esp, 0xC00A0000;high_init: ; 将要进入c编写的代码,此处还没有开中断,等到全部加载后便可开中断 jmp KERNEL_CS: 0xC0100000 ; jmp to kernel ;---------------------------------------------------------------------------; 以下定义数据;---------------------------------;加载到gdtr寄存器中,由于gdt_table会移动到线性地址0x00000800处,所以gdtr得基地址为0x00000800;---------------------------------tmpgdtr: dw 0x01FF ; gdt_table的16位界限 dd 0x00000800 ; 32位基地址, 此处为线性地址0x00000800gdtr: dw 0x01FF ; gdt_table的16位界限 dd 0xC0000800 ; 32位基地址, 此处为虚拟地址地址0xC0000800 ; 中断描述符表暂时还没有用idtr: dw 0 dd 0x1000 ;---------------------------------;gdt段描述表 (每段占8bytes);---------------------------------gdt_tablegdt_null ; dd 0 ; dd 0 ; k_code_gdt ; 内核代码段描述符 dw 0x0ffff ; 段限为4GB dw 0x0000 ; 段基址(0-15) L db 0x00 ; 段基址(16-23) M db 0x09a ; 可读可执行代码段,ring0,尚未受到访问 db 0x0cf ; 粒度为4k, 32位指令,四个段都在内存,段限为4GB db 0x00 ; 段基址(24-31)H k_data_gdt ; 内核数据段描述符 dw 0x0ffff ; 段限为4GB dw 0x0000 ; 段基址(0-15) L db 0x00 ; 段基址(16-23) M db 0x092 ; 可读可写数据段,ring0,尚未受到访问 db 0x0cf ; 粒度为4k, 段限为4GB db 0x00 ; 段基址(24-31)H u_code_gdt ; 用户代码段描述符 dw 0x0ffff ; 段限为4GB dw 0x0000 ; 段基址(0-15) L db 0x00 ; 段基址(16-23) M db 0x0fa ; 可读可执行代码段,ring3,尚未受到访问 db 0x0cf ; 粒度为4k, 32位指令,四个段都在内存,段限为4GB db 0x00 ; 段基址(24-31)H u_data_gdt ; 用户数据段描述符 dw 0x0ffff ; 段限为4GB dw 0x0000 ; 段基址(0-15) L db 0x00 ; 段基址(16-23) M db 0x0f2 ; 可读可写数据段,ring3,尚未受到访问 db 0x0cf ; 粒度为4k, 段限为4GB db 0x00 ; 段基址(24-31)H gdt_no_use ; dd 0 ; dd 0 ;gdt_end ;null_sel equ gdt_null - gdt_table ;KERNEL_CS equ k_code_gdt - gdt_table ; KERNEL_CS = 8hKERNEL_DS equ k_data_gdt - gdt_table ; KERNEL_DS = 10h USER_CS equ u_code_gdt - gdt_table ; USER_CS = 18hUSER_DS equ u_data_gdt - gdt_table ; USER_DS = 20h boot_msg db "Starting Fairy Sky", 0err_msg db 10, 13, "Kernel loading error!", 0 mem_too_small db 10, 13, "Memory is too small, die!", 0get_mem_size_err_msg db 10, 13, "Get memory failed, die!", 0boot_drv db 0 ; 启动驱动器号retries db 3 ; 启动时读磁盘失败的重试次数kernel_sectors dw 523 ; 内核所占的扇区数,变量times 1024 - ($ - $$) db 0 ; 填充两个扇区;;引导到此结束
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -