2017-06-28 1 views
-1

Je développe un OS minuscule à https://github.com/Incarnation-p-lee/excalibur. Récemment, lors de l'activation de la page, j'ai trouvé une différence de sortie lors de l'accès à la mémoire sur 1280 Mo. Supposons un code de suivi:Pourquoi OS image a un comportement différent lors de l'accès à la mémoire autour de 1280 Mo (0x50000000)

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 ... 
? 

Mais quand je veux accéder 0x4ffffffc, il a déclenché erreur de page? Il s'attendait que 0x4ffffffc et 0x50000000 déclenchent une erreur de page dans mon option.

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 ... 
? 

Code connexes et définition la structure

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 config

# 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

Vous semblez avoir l'interruption 13 (défaut de protection générale) au lieu de l'interruption 14 (erreur de page). Je suppose que c'est quelque chose à voir avec la façon dont vous avez configuré les descripteurs de segment, mais sans voir votre code, je ne peux pas le dire avec certitude. Dans tous les cas, le manuel d'architecture x86 vous expliquera en détails douloureux exactement quand vous obtenez une interruption par rapport à l'autre; Si vous écrivez un système d'exploitation à partir de zéro, vous devriez connaître le manuel d'architecture par cœur. – zwol

+2

Ne postez pas d'images de texte! – Olaf

+0

Je vais mettre à jour plus d'informations plus tard, ainsi que de remplacer l'image. Merci à tous, et je dois prendre soin de mon petit bébé pour l'instant et poster plus de code plus tard. MERCI ENCORE! –

Répondre

0

Edit: Je suis désolé, je confondais l'ordre de la segmentation et la pagination lors de la traduction de l'adresse ..

+0

Je ne pense pas que ce soit le point du problème, dans l'architecture x86, la fin de l'adresse d'accès avec 0xffd est valide. ici, je m'attends à déclencher une erreur de page mais déclenché GPF. Pour malentendu, je change l'adresse à 0x50000000 dans le code de test. –

0

Enfin, j'ai trouvé la cause première de ce problème. D'accord avec zwol, c'est un bug lors de la configuration de la table gdt, la limite et la base doivent être config avec 4KB en nombre. mais pas dans les octets. C'est pourquoi la mémoire de plus de 0x50000000 a déclenché le GPF mais pas la faute de page.