2017-06-28 6 views
-1

https://github.com/Incarnation-p-lee/excaliburに小さなOSを1つ開発しています。最近、ページを有効にすると、1280 MBのメモリにアクセスすると1つの差分出力が見つかりました。次のコードを仮定してください:1280 MB(0x50000000)のメモリにアクセスすると、osイメージの動作が異なる理由

static inline void 
test_paging(void) 
{ 
    uint32 *ptr; 

    // ptr = (void *)0x800000; 
    // *ptr = 0xdeadbeaf; 
    // ptr = (void *)0x4ffffffc; 
    ptr = (void *)0x50000000; 
    *ptr = 0xdeadbeaf; 
} 
[0x00000000] Boot loader magic -> 0x2badb002. 
[0x00000000] In Protect Mode. 
[0x00000000] Paging disabled. 
[0x00000000] OS image start -> 0x00100000 
[0x00000000] OS image end -> 0x00109000 
[0x00000000] Stack base 0x00100fb4. 
[0x00000000] Physical memory lower -> 0000000636 KB. 
[0x00000000] Physical memory upper -> 0000261056 KB. 
[0x00000000] GDT table initialized. 
[0x00000000] IDT table initialized. 
[0x00000000] IRQ timer initialized. 
[0x00000003] Page enabled from 0x00000000 -> 0x0011c004. 
[0x0000000b] Page initialized. 
[0x0000000b] In Protect Mode. 
[0x0000000b] Paging enabled. 
[0x0000000b] Divide by zero at eip -> 0x00101071. 
[0x0000000b] Breakpoint at eip -> 0x00101072. 
[0x0000000b] Divide by zero at eip -> 0x00101074. 
[0x0000000b] Unsupported isq 0000000013. 
Assertion: Unsupported ISR 
fail. 
    at function isr_handler_main 
    in file src/interrupt/isr/isr_handler.c:0000000014 
Enter KERNEL PANIC T.T ... 
? 

しかし、私は0x4ffffffcにアクセスしたいとき、ページフォールトを引き起こしましたか?私のオプションでは、0x4ffffffcと0x50000000の両方がページフォールトを引き起こすはずです。

static inline void 
test_paging(void) 
{ 
    uint32 *ptr; 

    // ptr = (void *)0x800000; 
    // *ptr = 0xdeadbeaf; 
    ptr = (void *)0x4ffffffc; 
    // ptr = (void *)0x50000000; 
    *ptr = 0xdeadbeaf; 
} 
[0x00000000] In Protect Mode. 
[0x00000000] Paging disabled. 
[0x00000000] OS image start -> 0x00100000 
[0x00000000] OS image end -> 0x00109000 
[0x00000000] Stack base 0x00100fb4. 
[0x00000000] Physical memory lower -> 0000000636 KB. 
[0x00000000] Physical memory upper -> 0000261056 KB. 
[0x00000000] GDT table initialized. 
[0x00000000] IDT table initialized. 
[0x00000000] IRQ timer initialized. 
[0x00000003] Page enabled from 0x00000000 -> 0x0011c004. 
[0x00000006] Page initialized. 
[0x00000006] In Protect Mode. 
[0x00000006] Paging enabled. 
[0x00000006] Divide by zero at eip -> 0x00101071. 
[0x00000006] Breakpoint at eip -> 0x00101072. 
[0x00000006] Divide by zero at eip -> 0x00101074. 
Page is not present. 
Page is Read-Only. 
Page Fault at address 0x4ffffffc. 
Assertion: Page Fault fail. 
    at function isr_14_paging_fault_handler 
    in file src/interrupt/isr/isr_handler.c:0000000076 
Enter KERNEL PANIC T.T ... 
? 

関連コードと構造体定義

void 
descriptor_table_gdt_initialize(void) 
{ 
    gdt_reg.limit = sizeof(gdt) - 1; 
    gdt_reg.base = (uint32)&gdt; 

    gdt_entry_set(0, 0, 0, 0, 0); 
    gdt_entry_set(1, CODE_SEG_BASE, CODE_SEG_LMT, CODE_SEG_ACC, CODE_SEG_FLAG); 
    gdt_entry_set(2, DATA_SEG_BASE, DATA_SEG_LMT, DATA_SEG_ACC, DATA_SEG_FLAG); 
    gdt_entry_set(3, 0, USR_CODE_SEG_LMT, USR_CODE_SEG_ACC, USR_CODE_SEG_FLAG); 
    gdt_entry_set(4, 0, USR_DATA_SEG_LMT, USR_DATA_SEG_ACC, USR_DATA_SEG_FLAG); 

    gdt_table_flush((uint32)&gdt_reg); 

    printf_vga_tk("GDT table initialized.\n"); 
} 

static inline void 
gdt_entry_set(uint32 i, uint32 base, uint32 limit, uint16 acc, uint8 flags) 
{ 
    kassert(i < GDT_ENTRY_CNT); 

    gdt[i].base_l = U32_BITS(base, 0, 24); 
    gdt[i].base_h = (uint8)U32_BITS(base, 24, 8); 

    gdt[i].lmt_l = (uint16)U32_BITS(limit, 0, 16); 
    gdt[i].flags.lmt_h = (uint8)U32_BITS(limit, 16, 4); 

    gdt[i].access.acc = (uint8)U32_BIT(acc, ACC_AC_IDX); 
    gdt[i].access.rw = (uint8)U32_BIT(acc, ACC_RW_IDX); 
    gdt[i].access.dc = (uint8)U32_BIT(acc, ACC_DC_IDX); 
    gdt[i].access.ex = (uint8)U32_BIT(acc, ACC_EX_IDX); 
    gdt[i].access.dt = (uint8)U32_BIT(acc, ACC_DT_IDX); 
    gdt[i].access.dpl = (uint8)U32_BITS(acc, ACC_DPL_IDX, ACC_DPL_LEN); 
    gdt[i].access.p = (uint8)U32_BIT(acc, ACC_P_IDX); 

    gdt[i].flags.avl = (uint8)U32_BIT(flags, FLAG_A_IDX); 
    gdt[i].flags.pack = 0; 
    gdt[i].flags.db = (uint8)U32_BIT(flags, FLAG_DB_IDX); 
    gdt[i].flags.g = (uint8)U32_BIT(flags, FLAG_G_IDX); 
} 

#define U32_BIT(x, idx)   ((uint32)(x) >> (idx) & 0x1) 
#define U32_BITS(x, s, l)   (((uint32)(x) >> (s)) & ((0x1 << (l)) - 1)) 

#define CODE_SEG_BASE    0x0 
#define CODE_SEG_LMT    0xffffffff 

#define DATA_SEG_BASE    0x0 
#define DATA_SEG_LMT    0xffffffff 

#define STACK_SEG_BASE   0x300000 
#define STACK_SEG_LMT    0xfffff 

#define USR_CODE_SEG_LMT   0xffffffff 
#define USR_DATA_SEG_LMT   0xffffffff 

static s_gdt_entry_t gdt[GDT_ENTRY_CNT]; 
static s_gdt_register_t gdt_reg; 

extern void gdt_table_flush(uint32); 

[GLOBAL gdt_table_flush] 
gdt_table_flush: 
    mov  eax, [esp + 4] 
    lgdt  [eax] 

    mov  ax, 0x10  ; data segment selector 
    mov  ds, ax 
    mov  es, ax 
    mov  fs, ax 
    mov  gs, ax 
    mov  ss, ax 

    jmp  0x8: .flush ; will change cs register implicitly 
.flush: 
    ret 

/* 
* Global Descriptor Table Register 
* 47       16 15     0 
* +----------------------------+-------------------+ 
* | 32-bit Linear Base Address | 16-bit Table Limit| 
* +----------------------------+-------------------+ 
*/ 
struct gdt_register { 
    uint16 limit; 
    uint32 base; 
} __attribute__((packed)); 

/* 
* Descriptor Attribute 
* 15 14 13 12 11    8 7 6 5 4 3 2 1 0 
* +---+-----+---+-----+----------------+---+-----+----+----+----+----+----+ 
* | G | D/B | 0 | AVL | Seg limit high | P | DPL | DT | EX | DC | RW | AC | 
* +---+-----+---+-----+----------------+---+-----+----+----+----+----+----+ 
*/ 
struct gdt_attribute_access { 
    uint8 acc:1; // Segment has been accessed or not 
    uint8 rw:1; // Read-only or Read/Write 
    uint8 dc:1; // Direction for data segment, 0 grow up, 1 grow down or 
       // Execution for code segment, 0 indicate DPL and more DPL 
       //        1 indicate only the DPL specify 
    uint8 ex:1; // Segment can be executed or not. 
    uint8 dt:1; // Descriptor Type, always 1 for GDT 
    uint8 dpl:2; // Descriptor privilege level, ring 0-3 
    uint8 p:1; // Segment is present or not 
} __attribute__((packed)); 

struct gdt_attribute_flags { 
    uint8 avl:1; 
    uint8 pack:1; 
    uint8 db:1; // Operand size, 0 16-bit 1 32-bit 
    uint8 g:1;  // Granularity which defines the limit unit in byte or 4KB 
    uint8 lmt_h:4; // High 4 bit of limit, bit <16, 19> of limit 
} __attribute__((packed)); 

/* 
* Global Descriptor Table Entry (Global Descriptor) 
* Each represent a segment in GDT. 
* 63   55  51   47  39   15   0 
* +-----------+-------+------------+--------+----------+-----------+ 
* | base high | flags | limit high | access | base low | limit low | 
* +-----------+-------+------------+--------+----------+-----------+ 
* base contains 32-bit 
* limit contains 20-bit 
*/ 
struct gdt_entry { 
    uint16      lmt_l; 
    uint32      base_l:24; 
    struct gdt_attribute_access access; 
    struct gdt_attribute_flags flags; 
    uint8      base_h; 
} __attribute__((packed)); 

Bochsの設定

# configuration file generated by Bochs 
plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1, gameport=1 
config_interface: win32config 
display_library: win32 
memory: host=256, guest=256 
romimage: file="C:\Program Files (x86)\Bochs-2.6.8/BIOS-bochs-latest" 
vgaromimage: file="C:\Program Files (x86)\Bochs-2.6.8/VGABIOS-lgpl-latest" 
boot: floppy 
floppy_bootsig_check: disabled=0 
floppya: type=1_44, 1_44="C:\Users\pli\Desktop\workspace\bochs\floppy.img", status=inserted, write_protected=0 
# no floppyb 
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 
ata0-master: type=none 
ata0-slave: type=none 
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 
ata1-master: type=none 
ata1-slave: type=none 
ata2: enabled=0 
ata3: enabled=0 
pci: enabled=1, chipset=i440fx 
vga: extension=vbe, update_freq=5, realtime=1 
cpu: count=1, ips=1000000, model=bx_generic, reset_on_triple_fault=0, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0 
cpuid: level=6, stepping=3, model=3, family=6, vendor_string="GenuineIntel", brand_string="    Intel(R) Pentium(R) 4 CPU  " 
cpuid: mmx=1, apic=xapic, simd=sse2, sse4a=0, misaligned_sse=0, sep=1, movbe=0, adx=0 
cpuid: aes=0, sha=0, xsave=0, xsaveopt=0, x86_64=1, 1g_pages=0, pcid=0, fsgsbase=0 
cpuid: smep=0, smap=0, mwait=1, vmx=1 
print_timestamps: enabled=0 
port_e9_hack: enabled=0 
private_colormap: enabled=0 
clock: sync=realtime, time0=local, rtc_sync=0 
# no cmosimage 
# no loader 
log: bochsout.txt 
logprefix: %t%e%d 
debug: action=ignore 
info: action=report 
error: action=report 
panic: action=ask 
keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none 
mouse: type=ps2, enabled=0, toggle=ctrl+mbutton 
sound: waveoutdrv=win, waveout=none, waveindrv=win, wavein=none, midioutdrv=win, midiout=none 
speaker: enabled=1, mode=sound 
parport1: enabled=1, file=none 
parport2: enabled=0 
com1: enabled=1, mode=null 
com2: enabled=0 
com3: enabled=0 
com4: enabled=0 
+3

割り込み14(ページフォールト)ではなく、割り込み13(一般保護フォルト)が発生しているようです。私はこれがあなたがセグメント記述子を設定したやり方と関係があると思いますが、あなたのコードを見ることなく、私は確実にはわかりません。いずれにしても、x86アーキテクチャのマニュアルでは、割り込みと割り込みを正確に区別して説明します。あなたが一からOSを書いているなら、心からアーキテクチャマニュアルを知っておくべきです。 – zwol

+2

テキストの画像を投稿しないでください! – Olaf

+0

後で詳細を更新し、イメージを置き換えます。ありがとうございました。私は今は少し赤ちゃんに気を配り、後でコードを投稿する必要があります。再度、感謝します! –

答えて

0

編集:私は非常に申し訳ないアドレスを変換するとき、私はセグメンテーションとページングの秩序を混乱さ..

+0

私はそれが問題のポイントだとは思わない、x86アーキテクチャでは、0xffdのアクセスアドレスの最後が有効である。ここでは、私はページ違反を引き起こすと予想しますが、GPFを引き起こします。誤解のために、テストコードでアドレスを0x50000000に変更します。 –

0

最後に、この問題の根本原因を発見しました。 zwolに同意すると、gdtテーブルを設定するときのバグです。制限とベースは4KBの設定で設定する必要があります。バイト単位ではありません。そのため、メモリが0x50000000より大きいとGPFがトリガされますが、ページフォルトはトリガされませんでした。