0から作るソフトウェア開発
日々勉強中。。。 |
Follow @Nina_Petipa |
0から作るOS開発 物理メモリ管理その1 物理メモリとマルチブート仕様 |
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ; ; Get Big Memory Size ; return : AX : size of memory between 1MB and 16MB (1KB unit) ; BX : size of memory above 16MB (64KB unit) ; CX : size of memory between 1MB and 16MB (1KB unit) ; DX : size of memory above 16MB (64KB unit) ; ; AX : -1 if error occurs ; ;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
BIOSGetBigMemorySize: PUSH EDX PUSH ECX XOR ECX, ECX XOR EDX, EDX MOV AX, 0xE801 INT 0x15 ; INT 0x15命令 JC .ERROR ; CFが0の場合はエラー CMP AH, 0x86 ; エラーステータスあるか調べる JE .ERROR ; エラーステータスがあればエラー CMP AH, 0x80 JE .ERROR JCXZ .RETURN_SIZE ; EXCが0なら.RETURN_SIZEへ MOV AX, CX ; メモリサイズをAXへ MOV BX, DX ; メモリサイズをBXへ .RETURN_SIZE ; メモリサイズはAX、BXに格納されている POP ECX POP EDX RET .ERROR ; エラー処理 MOV AX, -1 ; AXに-1を格納 MOV BX, 0 : BXにを格納 POP ECX POP EDX RET
メモリマップ情報(Address Range Descriptor) | |||
---|---|---|---|
バイト | ラベル名 |
サイズ (バイト) |
説明 |
0-7 | Base Address | 8 | メモリのベースアドレスが格納されます |
8-15 | Length | 8 | メモリのサイズがバイト単位で格納されます |
16-20 | Type | 4 |
メモリのタイプが格納されます 0x0001:OSが使用できるメモリです 0x0002:利用できないメモリです(ROMやメモリマップドデバイスなど) 0x0003:ACPI用のメモリです(ACPI情報を読みだした後はOSで利用できます) 0x0004:利用できないメモリです(ACPI NVSセッション用) 上記以外:利用できないメモリです(未定義のタイプ) |
struc MemoryMapEntry
.baseAddress resq 1
.length resq 1
.type resd 1
.acpi_null resd 1
endstruc
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ; ; get available memory space ; ;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
[BITS 16] BiosGetMemoryMap: PUSHAD XOR EBX, EBX XOR BP, BP ; メモリマップ情報のエントリ数をBPに入れる MOV EDX, 'PAMS' ; ”SMAP” MOV EAX, 0xE820 MOV ECX, 24 ; MemoryMapEntryのバイトサイズ INT 0x15 ; メモリマップ情報を取得 JC .ERROR ; エラー時は.ERRORへ CMP EAX, 'PAMS' ; BIOSが”SMAP”をしたか調べる JNE .ERROR ; ”SMAP”ではないときは.ERRORへ TEST EBX, EBX ; 戻り値EBXが0のときはメモリ情報は無し JE .ERROR JMP .START ; メモリマップ情報を格納する .NEXT_ENTRY: MOV EDX, 'PAMS' ; EDSにもう一度”SMAP”入れておく MOV ECX, 24 ; MemoryMapEntryのバイトサイズ MOV EAX, 0xE820 INT 0x15 ; 次のメモリマップ情報を取得 .START: JCXZ .SKIP_ENTRY ; CFが0のときは失敗なので戻り値を格納しない .NOTNEXT: MOV ECX, [ES:DI + MemoryMapEntry.length] ; BIOSが格納した ; メモリマップ情報のLengthを取得 ; (下位4バイト分) TEST ECX, ECX ; Length(下位4バイト)が0かどうか調べる JNE SHORT .GOOD_ENTRY ; 0じゃなければ.GOOD_ENTRYへ MOV ECX, [ES:DI + MemoryMapEntry.length + 4]; BIOSが格納した ; メモリマップ情報のLengthを取得 ; (上位4バイト分) JECXZ .SKIP_ENTRY ; Length(上位4バイト)が0なら.SKIP_ENTRYへ .GOOD_ENTRY: INC BP ; メモリマップ情報のエントリ数をインクリメント ADD DI, 24 ; 格納先ポインタを進める(MemoryMapEntryは24バイト) .SKIP_ENTRY: CMP EBX, 0 ; EBXが0ならこれ以上メモリマップ情報は無し JNE .NEXT_ENTRY ; 次候補がある場合は.NEXT_ENTRYへ JMP .MM_DONE ; 終了 .ERROR: STC ; CFフラグをセット .MM_DONE: POPAD RET
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ; ; Starting Kernel Procedure ; ;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
MAIN2:
; MAIN2の続きでプロテクティッドモードに以降する前
GET_MEMORY_MAP: XOR AX, AX ; メモリマップ情報取得で使用するレジスタを初期化 MOV ES, AX MOV DS, AX PUSH DI ; DIを退避しておく MOV EAX, DWORD mme ; MemoryMapEntryの先頭アドレスを取得 MOV DI, AX ; DIに入れておく CALL BiosGetMemoryMap ; メモリマップ情報取得 POP DI
; プロテクティッドモードへ以降していく ;--------------------------------------------------------------------------------- ; ; Memory Map Entry ; ;---------------------------------------------------------------------------------
struc MemoryMapEntry .baseAddress resq 1 .length resq 1 .type resd 1 .acpi_null resd 1 endstruc mme: istruc MemoryMapEntry at MemoryMapEntry.baseAddress, dd 0 at MemoryMapEntry.length, dd 0 at MemoryMapEntry.type, dd 0 at MemoryMapEntry.acpi_null, dd 0 iend
struc MemoryMapEntry
.baseAddress resq 1
.length resq 1
.type resd 1
.acpi_null resd 1
endstruc
typedef struct
{
unsigned long long baseAddress;
unsigned long long length;
unsigned long type;
unsigned long acpi_null;
} MemoryMapEntry;
mme:
istruc MemoryMapEntry
at MemoryMapEntry.baseAddress, dd 0
at MemoryMapEntry.length, dd 0
at MemoryMapEntry.type, dd 0
at MemoryMapEntry.acpi_null, dd 0
iend
static MemoryMapEntry mme;
PUSH DI ; DIを退避しておく
MOV EAX, DWORD mme ; MemoryMapEntryの先頭アドレスを取得←
MOV DI, AX ; DIに入れておく
CALL BiosGetMemoryMap ; メモリマップ情報取得
ブート情報 | |||
---|---|---|---|
ラベル名 |
オフセット (バイト) |
サイズ (バイト) |
説明 |
flags | 0 | 4 |
ブート情報のフィールドが有効/無効(有り/無し)のフラグです 各ビットが1になっていれば有効(有り)で、0であれば無効(無し)となります ビット0:1であればmem_*フィールドが有効になります ビット1:1であればboot_deviceフィールドが有効になります ビット2:1であればcmdlineフィールドが有効になります ビット3:1であればmods_*フィールドが有効になります ビット4:1であればsymフィールドがa.outカーネルイメージ用の フォーマットになります ビット5:1であればsymフィールドがELFカーネルイメージ用の フォーマットになります ビット6:1であればmmap_*フィールドが有効になります ビット7:1であればdrives_*フィールドが有効になります ビット8:1であればconfig_tableフィールドが有効になります ビット9:1であればboot_loader_nameフィールドが有効になります ビット10:1であればapm_tableフィールドが有効になります ビット11:vbe_*フィールドが有効になります |
mem_lower | 4 | 4 | ローメモリのメモリサイズが格納されています |
mem_upper | 8 | 4 | 拡張メモリ(1MB以降のメモリ領域)のメモリサイズが格納されています |
mmap_length | 44 | 4 | メモリマップ情報のデータ長が格納されています |
mmap_addr | 48 | 4 | メモリマップ情報が格納されているアドレスが格納されています |
;multi boot info
struc multiboot_info
.flags resd 1
.mem_lower resd 1
.mem_upper resd 1
.bootDevice resd 1
.cmdline resd 1
.mods_count resd 1
.mods_addr resd 1
.syms0 resd 1
.syms1 resd 1
.syms2 resd 1
.reserved resw 1
.mmap_length resd 1
.mmap_addr resd 1
.drives_length resd 1
.drives_addr resd 1
.config_table resd 1
.bootloader_name resd 1
.apm_table resd 1
.vbe_control_info resd 1
.vbe_mode_info resd 1
.vbe_mode resw 1
.vbe_interface_seg resw 1
.vbe_interface_off resw 1
.vbe_interface_len resw 1
endstruc
boot_info:
istruc multiboot_info
at multiboot_info.flags, dd 0
at multiboot_info.mem_lower, dd 0
at multiboot_info.mem_upper, dd 0
at multiboot_info.boot_device, dd 0
at multiboot_info.cmdline, dd 0
at multiboot_info.mods_count, dd 0
at multiboot_info.mods_addr, dd 0
at multiboot_info.syms0, dd 0
at multiboot_info.syms1, dd 0
at multiboot_info.syms2, dd 0
at multiboot_info.reserved, dw 0
at multiboot_info.mmap_length, dd 0
at multiboot_info.mmap_addr, dd 0
at multiboot_info.drives_length, dd 0
at multiboot_info.drives_addr, dd 0
at multiboot_info.config_table, dd 0
at multiboot_info.bootloader_name, dd 0
at multiboot_info.apm_table, dd 0
at multiboot_info.vbe_control_info, dd 0
at multiboot_info.vbe_mode_info, dd 0
at multiboot_info.vbe_mode, dw 0
at multiboot_info.vbe_interface_seg, dw 0
at multiboot_info.vbe_interface_off, dw 0
at multiboot_info.vbe_interface_len, dw 0
iend
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ; ; get available memory space ; ;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
[BITS 16] BiosGetMemoryMap:
; 0xE820機能でメモリマップ情報を取得します
.done: MOV [boot_info+multiboot_info.mmap_length], BP ; BPはメモリマップ情報の ; エントリ数が入っています ; boot_infoのmmap_lengthに格納します POPAD RET
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ; ; get available memory space ; ;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
GET_MEMORY_MAP: XOR AX, AX MOV ES, AX MOV DS, AX PUSH DI MOV EAX, DWORD mme MOV DI, AX CALL BiosGetMemoryMap POP DI MOV EAX, DWORD mme ; メモリマップ情報のアドレスを取得 MOV [boot_info+multiboot_info.mmap_addr], EAX ; メモリマップ情報のアドレスを ; mmap_addrに格納
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ; ; Starting Protected Mode ; ;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
[BITS 32] Pmode_start:
; プロテクティッドモード移行後の処理
EXECUTE:
;------------------------------------------- ; make boot info ;-------------------------------------------
;flags : flags[0] = 1, flgas[6] = 1 MOV EAX, 0x00000021 ; flagsのビット0とビット6を1にして ; flagsに格納します MOV [boot_info+multiboot_info.flags], EAX
;------------------------------------------- ; Execute Kernel ;-------------------------------------------
MOV EBX, IMAGE_PMODE_BASE MOV EBP, EBX MOV EAX, 0x2BADB002 XOR EBX, EBX CLI PUSH DWORD boot_info ; 引数としてboot_infoをカーネルに渡します CALL EBP ADD ESP, 4 ; 念のためスタック上の引数を除去しておく JMP Failure2
void function( int a )
{
// process of the function
}
int main( void )
{
function( 1000 );
}
PUSH DWORD a
CALL function
/********************************************************************************* File:bootinfo.h Description:definition of bootinfo *********************************************************************************/
#ifndef __BOOTINFO__H #define __BOOTINFO__H
/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ Description : Boot Information _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/ typedef struct { unsingned int flags; unsingned int mem_lower; unsingned int mem_upper; unsingned int boot_device; unsingned int cmdline; unsingned int mods_count; unsingned int mods_addr; unsingned int syms1; unsingned int syms2; unsingned int syms3; unsingned int mmap_length; unsingned int mmap_addr; unsingned int drives_length; unsingned int drives_addr; unsingned int config_table; unsingned int boot_loader_name; unsingned int apm_table; unsingned int vbe_control_info; unsingned int vbe_mode_info; unsingned short vbe_mode; unsingned short vbe_interface_seg; unsingned short vbe_interface_off; unsingned short vbe_interrace_len; } BOOTINFO; #endif /* __BOOTINFO__H */
/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ Funtion :_kernel_entry Input :BOOTINFO* info Output :void Return :void Description :Kernel Core _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */
int _kernel_entry( BOOTINFO* info ) { for( ;; ) { } }