我正在https://github.com/Incarnation-p-lee/excalibur开发一个小型操作系统。最近在启用页面时,访问1280 MB的内存时发现了一种不同的输出。假设遵循代码:
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
最佳答案
最后,我找到了此问题的根本原因。同意zwol,这是配置gdt表时的一个错误,限制和基数应该配置为4KB。但不以字节为单位。这就是为什么内存大于0x50000000会触发GPF而不触发页面错误的原因。
关于c - 为什么访问大约1280 MB(0x50000000)的内存时os镜像具有不同的行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44801225/