나는 내 자신의 커널을 구현하고 있는데, 막혔다. 커널을 상반부 가상 주소로로드하려고합니다. 나는 ID가 낮은 1M
의 RAM을 매핑하는 정체성 문제를 해결했습니다. 페이징 초기화를 처리하기 위해 커널의 물리적 주소로 재배치 된 init
섹션을 만들었습니다. 커널의 가상 오프셋은 0xc0000000
입니다. 이것은 제 링커 스크립트입니다 :페이징을 사용할 때 QEMU 트리플 폴트
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
KERNEL_VIRTUAL_OFFSET = 0xC0000000;
SECTIONS
{
. = 1M;
kernel_start = .;
start_init = .;
.init ALIGN(4K) :
{ *(.multiboot);
*(.init);
*(.tables);
}
end_init = .;
. += KERNEL_VIRTUAL_OFFSET;
kernel_high_half_start = .;
.text ALIGN(4K) : AT(ADDR(.text) - KERNEL_VIRTUAL_OFFSET)
{*(.text) }
.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_VIRTUAL_OFFSET)
{ *(.data) }
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_VIRTUAL_OFFSET)
{ *(.rodata) }
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_VIRTUAL_OFFSET)
{ *(.bss) }
kernel_high_half_end = .;
kernel_end = . - KERNEL_VIRTUAL_OFFSET;
}
여기 내 입장이 있습니다. GRUB을 부트 로더로 사용하고 있습니다.
its 32
section .multiboot
;grub bootloader header
align 4
dd 0x1BADB002 ;magic
dd 0x00 ;flags
dd - (0x1BADB002 + 0x00) ;checksum. m+f+c should be zero
; Declarations
global start
extern kmain
extern paging_init
extern kernel_page_directory
section .init
enable_paging:
mov eax, kernel_page_directory
mov cr3, eax
mov eax, cr0
or eax, 0x80000000
mov cr0, eax ; ***** PAGING ENABLED HERE *****
ret
start:
cli ;block interrupts
mov esp, init_stack
call paging_init
call enable_paging
;mov eax, 0xb8000
;mov byte[eax], 'h'
;mov byte[eax+1], 0x7
; Now high half kernel is mapped to the page directory
mov esp, stack_space ;set stack pointer
push ebx ; grub boot info
call kmain
loop:
hlt ;halt the CPU
jmp loop
resb 4096; 4KB small stack for my init section.
init_stack:
section .bss
resb 8192 ;8KB for stack
stack_space:
가 여기에 페이지 테이블과 커널의 페이지 디렉토리를 채우고 내 코드입니다 : 그것은 성공적으로 부팅되고 때문에 init
섹션의 내 진입 점으로 이동합니다. 당신이 볼 수 있듯이, 전체 코드는 이전 문제를 방지하기 위해 init
섹션으로 연결되어 있습니다 :
page_table_t kernel_page_directory[PAGE_DIR_SIZE]
__attribute__((aligned(PAGE_SIZE))) __attribute__((section(".tables"))) = {0};
page_pointer_t kernel_page_tables[PAGE_TABLE_SIZE]
__attribute__((aligned(PAGE_SIZE))) __attribute__((section(".tables"))) = {0};
page_pointer_t identity_page_table[PAGE_TABLE_SIZE]
__attribute__((aligned(PAGE_SIZE))) __attribute__((section(".tables"))) = {0};
/* Identity map the low 1M
* In early boot stage.
*/
static void __attribute__((section(".init"))) map_identity()
{
//map bios
unsigned int current_page = 0;
for(int i = 0; i < BIOS_PAGE_TABLE_ENTRIES; i++, current_page += PAGE_SIZE)
{
identity_page_table[i] = (current_page) | 0x3;
}
//map init
current_page = INIT_START;
for(int i = INIT_START >> 12 & 0x3FF;
i < ((INIT_START >> 12 & 0x3FF) + (INIT_SIZE/PAGE_SIZE));
i++, current_page += PAGE_SIZE)
{
identity_page_table[i] = (current_page) | 0x3;
}
kernel_page_directory[0] = ((unsigned long)(identity_page_table)) | 0x3;
}
/* Map the kernel memory to its page directory,
* **in early boot stage.
* We don't need to map the init section, we don't need it anymore.
*/
__attribute__((section(".init"))) static void map_kernel_memory()
{
//Identity map the init section
//Start at 1MB i.e. its page aligned.
unsigned int start_index = 256;
unsigned long current_page = KERNEL_START;
for(int i = start_index;
i < start_index + (KERNEL_SIZE/PAGE_SIZE) + 1;
i++, current_page += PAGE_SIZE)
{
kernel_page_tables[i] = current_page | 0x3;
}
kernel_page_directory[KERNEL_DIRECTORY_ENTRY] = ((unsigned long)kernel_page_tables) | 0x3;
}
__attribute__((section(".init"))) void paging_init()
{
map_identity();
map_kernel_memory();
}
나는 정확한 어셈블리 명령어를 가리려고 노력을하지만 잘못 내 커널 작업을하고 나는 그것이 있기 때문에 생각 페이징을 활성화하면 mov cr0, eax
입니다. CR3
에는 kernel_page_directory
또는 0x3
의 주소가 포함되어 있습니다. 페이징을 사용하자마자 QEMU는 응답을 중지하고 시스템이 계속 재부팅됩니다. 화면이 비우고 반복적으로 인쇄됩니다. 왜 이런 일이 일어나고 있는거야? 어떻게 해결할 수 있습니까?
최소한의 완전한 입증 가능한 예제를 제공하는 것이 도움이 될 수 있습니다. 모든 _C_ 파일 (일부분)을 제공하지 않고 사용중인 정의를 제공하지 않았습니다. 나는 어떤 것이 무엇인지 추측 할 수 있지만, 올바르게 정의되었는지는 알 수 없습니다. 누구나 독립적으로 컴파일/어셈블/링크 할 수 있도록 충분한 코드를 제공합니다. 또한 이점 - 컴파일/어셈블/링크하는 데 사용하는 실제 명령은 무엇입니까? 그것도이 같은 질문에서 종종 귀중합니다. –
@MichaelPetch 디버깅이 끔찍한 밤 후에, 나는 해결책을 찾았다. 문제는 내가 직접 GRUB의 GDT를 사용하는 것이 었습니다. 내 추측은 reffering하는 선형 주소 중 하나가 내 페이지 디렉토리에 매핑되지 않았기 때문에 페이지 폴트 또는 정의되지 않은 동작이 발생했습니다. – Delights
[multiboot 사양] (https://www.gnu.org/software/grub/manual/multiboot/multiboot.html)에는 이러한 내용이 있습니다. 관련 인용문 : _GDTR 세그먼트 레지스터가 위에서 설명한대로 설정되어 있어도 'GDTR'이 유효하지 않을 수 있으므로 ** OS 이미지에 세그먼트 레지스터 **가로드되어서는 안됩니다 (** 동일한 값을 다시로드하는 경우에도 마찬가지입니다). ** 자신의 'GDT'를 설정할 때까지. ** _ –