; haribote-os boot asm ; TAB=4 VBEMODE EQU 0x118 ; 1024 x 768 x 24bitカラー BITPERPIXEL EQU 24 MEMORYMODEL EQU 6 ; 4ならインデックスカラー 6ならダイレクトカラー ; (画面モード一覧) ; 0x100 : 640 x 400 x 8bitカラー ; 0x101 : 640 x 480 x 8bitカラー ; 0x103 : 800 x 600 x 8bitカラー ; 0x105 : 1024 x 768 x 8bitカラー ; 0x107 : 1280 x 1024 x 8bitカラー ; 0x118 : 1024 x 768 x 24bitカラー BOOTPACK_CODE EQU 0x00280000 ; bootpackのロード先 ;DSKCAC EQU 0x00100000 ; ディスクキャッシュの場所 ;DSKCAC0 EQU 0x00008000 ; ディスクキャッシュの場所(リアルモード) SYSPAGEDIR EQU 0x00100000 ; BOOT_INFO関係 BOOTDRIVE EQU 0x0ff0 ; ブートセクタが設定する LEDS EQU 0x0ff1 VMODE EQU 0x0ff2 ; 色数に関する情報。何ビットカラーか? SCRNX EQU 0x0ff4 ; 解像度のX SCRNY EQU 0x0ff6 ; 解像度のY VRAM EQU 0x0ff8 ; グラフィックバッファの開始番地 ORG 0xc200 ; このプログラムがどこに読み込まれるのか ;ブートデバイスを保存 mov [BOOTDRIVE], dl ; VBE存在確認 MOV AX,0x9000 MOV ES,AX MOV DI,0 MOV AX,0x4f00 INT 0x10 CMP AX,0x004f JNE scrn320 ; VBEのバージョンチェック MOV AX,[ES:DI+4] CMP AX,0x0200 JB scrn320 ; if (AX < 0x0200) goto scrn320 ; 画面モード情報を得る MOV CX,VBEMODE MOV AX,0x4f01 INT 0x10 CMP AX,0x004f JNE scrn320 ; 画面モード情報の確認 CMP BYTE [ES:DI+0x19],BITPERPIXEL JNE scrn320 CMP BYTE [ES:DI+0x1b],MEMORYMODEL JNE scrn320 MOV AX,[ES:DI+0x00] AND AX,0x0080 JZ scrn320 ; モード属性のbit7が0だったのであきらめる ; 画面モードの切り替え MOV BX,VBEMODE | 0x4000 MOV AX,0x4f02 INT 0x10 MOV BYTE [VMODE],BITPERPIXEL ; 画面モードをメモする(C言語が参照する) MOV AX,[ES:DI+0x12] MOV [SCRNX],AX MOV AX,[ES:DI+0x14] MOV [SCRNY],AX MOV EAX,[ES:DI+0x28] MOV [VRAM],EAX JMP keystatus scrn320: MOV AL,0x13 ; VGAグラフィックス、320x200x8bitカラー MOV AH,0x00 INT 0x10 MOV BYTE [VMODE],8 ; 画面モードをメモする(C言語が参照する) MOV WORD [SCRNX],320 MOV WORD [SCRNY],200 MOV DWORD [VRAM],0x000a0000 ; キーボードのLED状態をBIOSに教えてもらう keystatus: MOV AH,0x02 INT 0x16 ; keyboard BIOS MOV [LEDS],AL ; PICが一切の割り込みを受け付けないようにする ; AT互換機の仕様では、PICの初期化をするなら、 ; こいつをCLI前にやっておかないと、たまにハングアップする ; PICの初期化はあとでやる MOV AL,0xff OUT 0x21,AL NOP ; OUT命令を連続させるとうまくいかない機種があるらしいので OUT 0xa1,AL CLI ; さらにCPUレベルでも割り込み禁止 ; CPUから1MB以上のメモリにアクセスできるように、A20GATEを設定 CALL waitkbdout MOV AL,0xd1 OUT 0x64,AL CALL waitkbdout MOV AL,0xdf ; enable A20 OUT 0x60,AL CALL waitkbdout ;[INSTRSET "i486p"] ; 486の命令まで使いたいという記述 ; プロテクトモード移行 ; page size = 4mb or 4kb (混在) pys addr size = 32 bit LGDT [GDTR0] ; 暫定GDTを設定 MOV EAX,CR0 ;or eax, 1 << 0x1f ; paging flag ;AND EAX,0x7fffffff ; bit31を0にする(ページング禁止のため) OR EAX,0x00000001 ; bit0を1にする(プロテクトモード移行のため) MOV CR0,EAX JMP pipelineflush pipelineflush: ;ページディレクトリ等の設定 xor eax, eax mov ecx, 0 align 16 pagedirloop: mov eax, ecx shl eax, 22 or eax, ((1 << 8)|(1 << 7)|(1 << 1)|1) mov [SYSPAGEDIR + 4 * ecx], eax inc ecx cmp ecx, 0x400 jb pagedirloop ;ページングの設定 mov eax, cr3 or eax, SYSPAGEDIR mov cr3, eax mov eax, cr4 and eax, ~(1 << 5) ; physical addr ext(pae) を無効に or eax, 1 << 4; enable paging size ext(pse) mov cr4, eax ;TLB無効化? mov eax, cr3 mov cr3, eax MOV EAX,CR0 or eax, 1 << 0x1f ; paging flag MOV CR0,EAX JMP pipelineflush2 pipelineflush2: MOV AX,1*8 ; 読み書き可能セグメント32bit MOV DS,AX MOV ES,AX MOV FS,AX MOV GS,AX MOV SS,AX ; ついでにディスクデータも本来の位置へ転送 ; まずはブートセクタから ;MOV ESI,0x7c00 ; 転送元 ;MOV EDI,DSKCAC ; 転送先 ;MOV ECX,512/4 ;CALL memcpy ; asmheadでしなければいけないことは全部し終わったので、 ; あとはbootpackに任せる ; bootpackの起動 MOV EBX, bootpack MOV ECX, [EBX+0x3C] ; lfanew add ebx, ecx ; nt header 32 mov ax, [ebx + 6] ; number of section mov ebp, [ebx + 0x28] ; entry point add ebp, BOOTPACK_CODE add ebx, 0xf8 ; section header readsection: mov edi, [ebx + 0x0C] ; virtual addr mov ecx, [ebx + 0x10] ; size of raw data mov esi, [ebx + 0x14] ; pointer to raw data add edi, BOOTPACK_CODE ; このセクションのコピー先 add esi, bootpack ; コピー元 cld a32 rep movsb ;db 0xf3 ;db 0x67 ;db 0xa4 ;rep dword movsb ; f3 a4 add ebx, 0x28 ; section header size dec ax jnz readsection MOV ESP, 0x00380000 ; スタック初期値 push dword 2*8 push ebp ;sti o32 retf ; call eipload ; eipload: ; pop ax ; movzx eax, ax ; mov [eax+0x15], ebp ; mov dword [eax+0x19], 2*8 ; jmp dword 0:0 ; db 0,0 waitkbdout: IN AL,0x64 AND AL,0x02 IN AL,0x60 ; から読み(受信バッファが悪さをしないように) JNZ waitkbdout ; ANDの結果が0でなければwaitkbdoutへ RET memcpy: push eax memcpy_loop: MOV EAX,[ESI] ADD ESI,4 MOV [EDI],EAX ADD EDI,4 SUB ECX,1 JNZ memcpy_loop ; 引き算した結果が0でなければmemcpyへ pop eax RET ; memcpyはアドレスサイズプリフィクスを入れ忘れなければ、ストリング命令でも書ける ALIGNB 16 GDT0: RESB 8 ; ヌルセレクタ db 0xff,0xff,0x00,0x00,0x00,0x92,0xcf,0x00 ; 読み書き可能セグメント32bit ;db 0xff,0xff,0x00,0x00,0x28,0x9a,0x4f,0x00 ; 実行可能セグメント32bit(bootpack用) db 0xff,0xff,0x00,0x00,0x00,0x9a,0xcf,0x00 ; 実行可能セグメント32bit(bootpack用) DW 0 GDTR0: DW 8*3-1 DD GDT0 ALIGNB 16 bootpack: