📄 setup.asm
字号:
;文件名: setup.asm;说明: 获取硬件信息,加载内核到0x10000处,进行分段,; 移动内核到0x100000处,进行分页,跳转到start_kernel中;作者: marsinfan;日期: 2005/12/29;---------------------------------------------------------------------------; 常量定义;---------------------------------------------------------------------------REAL_KERNEL_SEG EQU 0x1000 ; kernel加载到的段地址REAL_KERNEL_OFFSET EQU 0x0000 ; kernel加载到的段内偏移量SETUP_SEG EQU 0x9000 ; setup的段地址SETUP_OFFSET EQU 0x0000 ; setup加载到的段内偏移量SECTOR_SPER_TRACK EQU 18 ; 1.44M软盘的扇区数BYTE_SPERSECTOR EQU 512 ; 每扇区字节数LOAD_ADDR EQU 0x7C00 ; 引导程序地址 NEW_LOAD_ADDR EQU 0x0600 ; 移动后的引导程序地址 PARAM_ADDR EQU 0x0500 ; 硬件参数存放的地址 GDT_SEG EQU 0x0000 ; gdt的段地址GDT_0FFSET EQU 0x0800 ; gdt的段内偏移量PAGE_SIZE EQU 0x1000 ; 页表大小PAGE_DIR EQU 0x10000 ; 页目录地址PAGE_0_ADDR EQU 0x11000 ; 第一个页表地址PAGE_1_ADDR EQU 0x12000 ; 第二个页表地址PAGE_2_ADDR EQU 0x13000 ; 第三个页表地址PAGE_3_ADDR EQU 0x14000 ; 第四个页表地址;ADDRS_PAGE EQU 0x400 ; 每页表所容纳的地址数PAGE_OFFSET EQU 0xC0000000 ; 进行分页后,内核所在的虚拟地址SMAP EQU 0x534d4150E820MAX EQU 128 ; number of entries in E820MAPE820NR EQU PARAM_ADDR + 46[BITS 16][ORG 0x90000] mov ax, SETUP_SEG mov ds, ax mov es, ax mov si, boot_msg call print_msg mov ax, 0x0000; mov ds, ax mov es, ax ; 读取光标的坐标 mov ah, 0x03 ; xor bh, bh int 0x10 ; save it in known place, con_init fetches mov [PARAM_ADDR + 0], dx ; 光标的位置存放到PARAM_ADDR处 ; 取得物理内存大小 (1M以上的扩展内存, KB) mov ah, 0x88 int 0x15;;探测内存是否小于16M,如果小于,则提示并死机 cmp ax, 0x3C00 jae next mov ax, SETUP_SEG mov ds, ax mov si, mem_too_small ; call print_msg ; jmp $ next: add ax, 1024; shr ax, 2 ; 换成4k个数 shr ax, 10 ; 换成所需页目录项数 ;mov [PARAM_ADDR + 2], ax ; 16M的页目录项数存放到PARAM_ADDR + 2处 mov ax, 4 mov [PARAM_ADDR + 2], ax ; 16M的页目录项数存放到PARAM_ADDR + 2处; 取得video-card显示模式 mov ah, 0x0f int 0x10 mov [PARAM_ADDR + 4], bx ; bh = display page mov [PARAM_ADDR + 6], ax ; al = video mode, ah = window width ; 取得EGA/VGA配置参数 mov ah, 0x12 mov bl, 0x10 int 0x10 mov [PARAM_ADDR + 8], ax mov [PARAM_ADDR + 10], bx mov [PARAM_ADDR + 12], cx ;复制硬盘信息 lds si, [4 * 0x41]; mov di, PARAM_ADDR + 14 mov cx, 0x10; cld rep movsb;INT 15 E820 - newer BIOSes - GET SYSTEM MEMORY MAP;Inp.:; AX = E820h; EAX = 0000E820h; EDX = 534D4150h ('SMAP'); EBX = continuation value or 00000000h to start at beginning of map; ECX = size of buffer for result, in bytes (should be >= 20 bytes); ES:DI -> buffer for result (see #00560);Return: CF clear if successful; EAX = 534D4150h ('SMAP'); ES:DI buffer filled; EBX = next offset from which to copy or 00000000h if all done;; ECX = actual length returned in bytes; CF set on error; AH = error code (86h) (see #00475 at INT 15/AH=80h);Notes: originally introduced with the Phoenix BIOS v4.0, this function is; now supported by most newer BIOSes, since various versions of Windows; call it to find out about the system memory; a maximum of 20 bytes will be transferred at one time, even if ECX is; higher; some BIOSes (e.g. Award Modular BIOS v4.50PG) ignore the; value of ECX on entry, and always copy 20 bytes;;some BIOSes expect the high word of EAX to be clear on entry, i.e.; EAX=0000E820h; if this function is not supported, an application should fall back; to AX=E802h, AX=E801h, and then AH=88h; the BIOS is permitted to return a nonzero continuation value in EBX; and indicate that the end of the list has already been reached by; returning with CF set on the next iteration; this function will return base memory and ISA/PCI memory contiguous; with base memory as normal memory ranges; it will indicate;; chipset-defined address holes which are not in use and motherboard; memory-mapped devices, and all occurrences of the system BIOS as; reserved; standard PC address ranges will not be reported;SeeAlso: AH=C7h,AX=E801h"Phoenix",AX=E881h,MEM xxxxh:xxx0h"ACPI";;Format of Phoenix BIOS system memory map address range descriptor:;Offset Size Description (Table 00559); 00h QWORD base address; 08h QWORD length in bytes; 10h DWORD type of address range (see #00560);;(Table 00560);Values for System Memory Map address type:; 01h memory, available to OS; 02h reserved, not available (e.g. system ROM, memory-mapped device); 03h ACPI Reclaim Memory (usable by OS after reading ACPI tables); 04h ACPI NVS Memory (OS is required to save this memory between NVS; sessions); other not defined yet -- treat as Reserved; mov ax, 0x0000 mov ds, ax mov es, ax mov byte [E820NR], 0 ; E820 map数量清零 jmp meme820; bail820: ; 获取meme820失败,死机 mov ax, SETUP_SEG mov ds, ax mov si, get_mem_size_err_msg ; call print_msg ; jmp $ meme820: xor ebx, ebx ; continuation value or 00000000h to start at beginning of map ; Copied from Ralf Brown's Interrupt List mov di, PARAM_ADDR + 48 ; 获取内存信息存放的地址jmpe820: mov eax, 0x0000e820 ; 必须为 e820 mov edx, SMAP ; 必须为'SMAP' mov ecx, 20 ; e820结构的大小 int 0x15 ; 调用 0x15中断 jc bail820 ; 如果失败,则提示后死机 cmp eax, SMAP ; 检查调用返回值是否是`SMAP' jne bail820 ; 不是则表示调用失败,提示死机good820: mov al, byte [E820NR] ; 检查获取的E820 map数量, cmp al, E820MAX ; 如果超过128,说明有错误 jae bail820 inc byte [E820NR] ; E820 map数量加一 mov ax, di add ax, 20 ; 指向一下个存放E820map地址 mov di, axagain820: cmp ebx, 0 ; 检测ebx jne jmpe820 ; 如果不等于0表示后面还有内存需要检测 call cls ; 清屏 mov ax, SETUP_SEG mov ds, ax mov es, ax mov ah, 2 mov dx, 0 ; 光标的位置 0,0 mov bh, 0 ; video page 0 int 10h ; 设置cursor到 0,0 mov si, boot_msg ; call print_msg ; 显示"Starting Fairy Sky...",;开始加载内核load_kernel: mov ax, REAL_KERNEL_SEG ; 0x1000 mov es, ax xor bx, bx ; mov cx, 0x0004 ; ch = 磁道号, cl = 扇区号 mov dx, 0x0000 ; dh = 磁头号, dl = 驱动器号 mov ax, 1000 ; mov [kernel_sectors], ax ; 设置待读取的扇区数 call read_kernel_to_memory ; 从chs:002读取内核到0x1000处 ;对8259重新编程 mov al, 0x11 ; initialization sequence out 0x20, al ; send it to 8259A-1 dw 0x00eb, 0x00eb ; jmp $+2, jmp $+2 out 0xA0, al ; and to 8259A-2 dw 0x00eb, 0x00eb mov al, 0x20 ; start of hardware int's (0x20) out 0x21, al dw 0x00eb, 0x00eb mov al, 0x28 ; start of hardware int's 2 (0x28) out 0xA1, al dw 0x00eb, 0x00eb mov al, 0x04 ; 8259-1 is master out 0x21, al dw 0x00eb, 0x00eb mov al, 0x02 ; 8259-2 is slave out 0xA1, al dw 0x00eb, 0x00eb mov al, 0x01 ; 8086 mode for both out 0x21, al dw 0x00eb,0x00eb out 0xA1, al dw 0x00eb, 0x00eb mov al,0xFF ; mask off all interrupts for now out 0xA1, al dw 0x00eb, 0x00eb mov al, 0xFB ; mask all irq's but irq2 which out 0x21, al ; is cascaded ; 如果运行到这里代表已经完成内核的加载pre_goto_pm: call cls ; 清屏 mov dx, 0x3f2 mov al, 0x0c out dx, al ; 停止软驱 ;准备开始进入保护模式 cli ; 关中断 push es mov ax, GDT_SEG mov es, ax ; mov di, GDT_0FFSET mov si, gdt_table mov cx, gdt_end - gdt_table rep movsb ; 把gdt_table移动到0x0000:0x0800处 pop es lgdt [tmpgdtr] ; 加载GDT mov eax, cr0 or al, 0x01 mov cr0, eax ; 进入保护模式 ;打开A20,这样可以访问高1M的内存 in al, 0x92 or al, 2 out 0x92, al jmp dword KERNEL_CS: go_pm ; 跳到32位code中 ;---------------------------------------------------------------------------;工具函数定义 ;---------------------------------;打印字符串; print_msg: 利用BIOS中断(int 10h)进行写屏 ; 参数: si:字符串的首地址, 字符串以结尾
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -