Why os image has different behavior when accessing memory around 1280 MB(0x50000000)

-1

I am developing one tiny OS at https://github.com/Incarnation-p-lee/excalibur. Recently when enable page, I found one difference output when accessing memory across 1280 MB. Assume follow code:

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

But when I want to access 0x4ffffffc, it triggered page fault ? It expected both 0x4ffffffc and 0x50000000 should trigger page fault in my 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 ...
?

Related code and structure definition

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
c
operating-system
asmx
asked on Stack Overflow Jun 28, 2017 by Incarnation P. Lee • edited Jun 29, 2017 by Incarnation P. Lee

2 Answers

0

Edit: I'm very sorry,I confused the order of segmentation and paging when translating the address...

answered on Stack Overflow Jun 28, 2017 by sanslol • edited Jun 30, 2017 by sanslol
0

Finally, I found the root cause of this issue. Agree with zwol, it is a bug when config the gdt table, the limit and base should be config with 4KB in count. but not in bytes. That is why memory large than 0x50000000 triggered GPF but not page fault.

answered on Stack Overflow Jun 30, 2017 by Incarnation P. Lee

User contributions licensed under CC BY-SA 3.0