OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 2:54 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: Fix triple fault reboot for this paging code
PostPosted: Sun Apr 14, 2019 6:16 am 
Offline
Member
Member
User avatar

Joined: Tue Mar 06, 2007 11:17 am
Posts: 1225
I have this simple paging code.

CR3 points to the physical address page directory.

The first entry of the page directory points to the physical address of a page table.

The page table entries point to the physical addresses of the first 1024 4K pages.

Everything is 4K-aligned, but it reboots.

Here's the code that implements it, it seems completely OK but it reboots the machine, and I know that code like this will take me 1 or 2 weeks to fix on my own.

Code:
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization


cli

;Generate an empty page directory
;in a place we have proven to be empty
;and, if we have more than 16MB, put as much
;as we can of the paging structures there:
;;
mov widedi,kernel_page_window  ;Make this function dynamically get
                        ;a free page, but for that we need to
                        ;detect memory by different methods
                        ;before loading the kernel and record
                        ;the memory used by the kernel with a
                        ;memory management function set that
                        ;tell us if a given page is in a reserved
                        ;area or not. That's not the function
                        ;of paging itself but of basic memory detection,
                        ;and reserved areas defined by the PC (BIOS,
                        ;video, DMA, PCI, the first Megabyte, memory holes...).
                        ;It must record the area in an element with
                        ;value 0 (NULL) in the CR3 array, and an
                        ;index variable to indicate the currently active
                        ;CR3. Element 0 should always be the root CR3.
call OPCODE__CPU_generate_4KB_empty_page_directory  ;Take into account reserved regions from some subsystem and add complexity to it gradually


;Generate an entry in the page directory
;to a page table for the first 2 or 4 Megabytes:
;;
mov wideax,kernel_page_window+(4096*1)
or dword[widedi],_FLAG_x86_32_pageDirectoryEntry_Bit0_Present_TRUE
or dword[widedi],wideax



;Generate the addresses for the first 4MB
;in the first page table:
;;
mov widedi,kernel_page_window+(4096*1)   ;Address of page table
mov widecx,1024     ;1024 entries
xor wideax,wideax   ;Current address
or wideax,_FLAG_x86_32_pageDirectoryEntry_Bit0_Present_TRUE|_FLAG_x86_32_pageDirectoryEntry_Bit1_ReadWrite|_FLAG_x86_32_pageDirectoryEntry_Bit2_SupervisorLevel
align wideword_sz
.pgtbl0:
   stosd
   add wideax,4096
loop .pgtbl0



;Enable default 32-bit paging:
;;
mov wideax,kernel_page_window
call OPCODE__CPU_Enable_Default_Paging

hlt
sti

;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization




Code:
align 4096
kernel_page_window:
times 4096 db 0  ;Could be used as the kernel page directory
times 4096 db 0  ;Could be used as 1 entry of the kernel page directory (a page table)
times 4096 db 0  ;Could be used as 1 entry of the kernel page directory (a page table)
times 4096 db 0  ;Could be used as 1 entry of the kernel page directory (a page table)
times 4096 db 0  ;Could be used as 1 entry of the kernel page directory (a page table)




Code:
;Inputs:
;       WIDEDI -- 4KB-aligned memory address
;                 to place the generated page directory.
;
;
;;
OPCODE__CPU_generate_4KB_empty_page_directory:
push wideax
push widecx
pushfwide

  mov cr3,widedi

  mov wideax,_FLAG_x86_32_pageDirectoryEntry_Bit0_Present_FALSE|_FLAG_x86_32_pageDirectoryEntry_Bit1_ReadWrite|_FLAG_x86_32_pageDirectoryEntry_Bit2_SupervisorLevel
  mov widecx,1024
  rep stosd




popfwide
pop widecx
pop wideax
retwide





Code:
;Parameters:
;
; WIDEAX -- Page directory root
;
;
;
;;
;;;
;;;;
align wideword_sz
OPCODE__CPU_Enable_Default_Paging:
push wideax
pushfwide

;Load the page directory into CR3
;and store the kernel page directory
;in element 0 of the system's CR3 values array:
;;
  mov cr3,wideax
  mov [CR3_array],wideax


;Enable paging bit 31 in CR0.
;Bit 31 for paging makes thing as if
;paging was the best, most difficult
;thing from the x86 CPU, the last thing left
;that was done:
;;
  mov eax,cr0
  or eax,10000000_00000000_00000000_00000000b
  mov cr0,eax



popfwide
pop wideax
retwide




Code:
                                                        ;       -
_FLAG_x86_32_pageDirectoryEntry_Bit0_Present_TRUE    equ 00000001b
_FLAG_x86_32_pageDirectoryEntry_Bit0_Present_FALSE   equ 00000000b
                                                        ;       -
                                                        ;      -
_FLAG_x86_32_pageDirectoryEntry_Bit1_ReadWrite       equ 00000010b
_FLAG_x86_32_pageDirectoryEntry_Bit1_ReadOnly        equ 00000000b
                                                        ;      -
                                                        ;     -
_FLAG_x86_32_pageDirectoryEntry_Bit2_SupervisorLevel equ 00000000b
_FLAG_x86_32_pageDirectoryEntry_Bit2_UserLevel       equ 00000100b
                                                        ;     -
                                                        ;    -
_FLAG_x86_32_pageDirectoryEntry_Bit3_WriteBack       equ 00000000b
_FLAG_x86_32_pageDirectoryEntry_Bit3_WriteThrough    equ 00001000b
                                                        ;    -
                                                        ;   -
_FLAG_x86_32_pageDirectoryEntry_Bit4_DisableCache    equ 00010000b
_FLAG_x86_32_pageDirectoryEntry_Bit4_EnableCache     equ 00010000b
                                                        ;   -





                                          ;       -
CPU_x86_32_Paging_Bit0_Present_TRUE    equ 00000001b
CPU_x86_32_Paging_Bit0_Present_FALSE   equ 00000000b
                                          ;       -
                                          ;      -
CPU_x86_32_Paging_Bit1_ReadWrite       equ 00000010b
CPU_x86_32_Paging_Bit1_ReadOnly        equ 00000000b
                                          ;      -
                                          ;     -
CPU_x86_32_Paging_Bit2_SupervisorLevel equ 00000000b
CPU_x86_32_Paging_Bit2_UserLevel       equ 00000100b
                                          ;     -
                                          ;    -
CPU_x86_32_Paging_Bit3_WriteBack       equ 00000000b
CPU_x86_32_Paging_Bit3_WriteThrough    equ 00001000b
                                          ;    -
                                          ;   -
CPU_x86_32_Paging_Bit4_DisableCache    equ 00010000b
CPU_x86_32_Paging_Bit4_EnableCache     equ 00000000b
                                          ;   -
                                          ;  -
CPU_x86_32_Paging_Bit5_Accessed_FALSE  equ 00000000b
CPU_x86_32_Paging_Bit5_Accessed_TRUE   equ 00100000b
                                          ;  -
                                          ; -
CPU_x86_32_PageTable_Bit6_Dirty_FALSE  equ 00000000b
CPU_x86_32_PageTable_Bit6_Dirty_TRUE   equ 01000000b
                                          ; -
                                                      ;-
CPU_x86_32_PageTable_Bit7_PageAttributeTable_FALSE equ 00000000b
CPU_x86_32_PageTable_Bit7_PageAttributeTable_TRUE  equ 10000000b
                                                      ;-
                                              ;-
CPU_x86_32_PageTable_Bit8_GlobalPage_FALSE equ 0_00000000b
CPU_x86_32_PageTable_Bit8_GlobalPage_TRUE  equ 1_00000000b
                                              ;-
                                                     ;   -
CPU_x86_32_PageDir_Bit12_PageAttributeTable_FALSE equ 00000000_00000000b
CPU_x86_32_PageDir_Bit12_PageAttributeTable_TRUE  equ 00010000_00000000b
                                                     ;   -







                                       ;    ---
CPU_x86_32_Paging_Bit9_11_AVL_0     equ 00000000_00000000b
CPU_x86_32_Paging_Bit9_11_AVL_1     equ 00000010_00000000b
CPU_x86_32_Paging_Bit9_11_AVL_2     equ 00000100_00000000b
CPU_x86_32_Paging_Bit9_11_AVL_3     equ 00000110_00000000b
CPU_x86_32_Paging_Bit9_11_AVL_4     equ 00001000_00000000b
CPU_x86_32_Paging_Bit9_11_AVL_5     equ 00001010_00000000b
CPU_x86_32_Paging_Bit9_11_AVL_6     equ 00001100_00000000b
CPU_x86_32_Paging_Bit9_11_AVL_7     equ 00001110_00000000b
                                       ;    ---






Code:
;A certain number of CR3 registers mapped
;physically in the main kernel image should
;allow us to switch/swap address spaces enough.
;
;This needs to be aligned to 4096 since it's
;the most important thing to map globally in
;any paging directory, but the main kernel
;image should also be mapped, so it should be
;minimal/small, for what concerns the kernel:
;;
align 4096
CR3_array times 128 dd 0

CR3_index ww 0


_________________
Live PC 1: Image Live PC 2: Image

YouTube:
http://youtube.com/@AltComp126/streams
http://youtube.com/@proyectos/streams

http://master.dl.sourceforge.net/projec ... 7z?viasf=1


Last edited by ~ on Sun Apr 14, 2019 6:56 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Fix triple fault reboot for this paging code
PostPosted: Sun Apr 14, 2019 6:52 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
You seem to be using a non-standard syntax, so it's difficult to follow what your code is doing.

Anyway, you are best placed to debug it. Single-step the code in a debugger, examine the memory structures to see that they are correct, and examine the registers when the first exception occurs to determine the cause of the exception.

You'll learn far more by solving your own problem (and I would strongly advise you to stick to a conventional assembler syntax).


Top
 Profile  
 
 Post subject: Re: Fix triple fault reboot for this paging code
PostPosted: Mon Apr 15, 2019 11:56 am 
Offline
Member
Member
User avatar

Joined: Tue Mar 06, 2007 11:17 am
Posts: 1225
It's not nonstandard syntax, it's from a header to make portable the assembly source code so that it compiles readily across 16/32/64-bit modes with NASM (register sizes, some instructions and other machine word size details adjust automatically at assembly time according to the selected target mode, just like the CPU itself). I've appended the header file so that the code makes sense.
-----------------------------------------------

I've fixed the problem.

The bug was that I didn't save original EDI when finishing to build the page directory, so when returning from OPCODE__CPU_generate_4KB_empty_page_directory, it no longer pointed to the first entry of it to allocate a page table.

The new code:

Code:
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization
;;;;INIT: 32-bit Paging initialization


cli








;Generate an empty page directory
;in a place we have proven to be empty
;and, if we have more than 16MB, put as much
;as we can of the paging structures there:
;;
mov widedi,kernel_page_window  ;Make this function dynamically get
                        ;a free page, but for that we need to
                        ;detect memory by different methods
                        ;before loading the kernel and record
                        ;the memory used by the kernel with a
                        ;memory management function set that
                        ;tell us if a given page is in a reserved
                        ;area or not. That's not the function
                        ;of paging itself but of basic memory detection,
                        ;and reserved areas defined by the PC (BIOS,
                        ;video, DMA, PCI, the first Megabyte, memory holes...).
                        ;It must record the area in an element with
                        ;value 0 (NULL) in the CR3 array, and an
                        ;index variable to indicate the currently active
                        ;CR3. Element 0 should always be the root CR3.
call OPCODE__CPU_generate_4KB_empty_page_directory  ;Take into account reserved regions from some subsystem and add complexity to it gradually



;Generate an entry in the page directory
;to a page table for the first 2 or 4 Megabytes:
;;
mov wideax,kernel_page_window+(4096*1)
or dword[widedi],_FLAG_x86_32_pageDirectoryEntry_Bit0_Present_TRUE
or dword[widedi],wideax



;Generate the addresses for the first 4MB
;in the first page table:
;;
mov widedi,kernel_page_window+(4096*1)   ;Address of page table
mov widecx,1024     ;1024 entries
xor wideax,wideax   ;Current address
or wideax,_FLAG_x86_32_pageDirectoryEntry_Bit0_Present_TRUE|_FLAG_x86_32_pageDirectoryEntry_Bit1_ReadWrite|_FLAG_x86_32_pageDirectoryEntry_Bit2_SupervisorLevel
align wideword_sz
.pgtbl0:
   stosd
   add wideax,4096
loop .pgtbl0





;Enable default 32-bit paging:
;;
call OPCODE__CPU_Enable_Default_Paging











sti

;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization
;;;;END:  32-bit Paging initialization







Code:
;kernel_page_cache.asm

;db "kernel_page_window (debug string to remove)"
align 4096
kernel_page_window:
times 4096 db 0  ;Could be used as the kernel page directory
times 4096 db 0  ;Could be used as 1 entry of the kernel page directory (a page table)
times 4096 db 0  ;Could be used as 1 entry of the kernel page directory (a page table)
times 4096 db 0  ;Could be used as 1 entry of the kernel page directory (a page table)
times 4096 db 0  ;Could be used as 1 entry of the kernel page directory (a page table)

;times 4096 db 0  ;Could be used as 1 memory page to be constantly relocated (for source data)
;times 4096 db 0  ;Could be used as 1 memory page to be constantly relocated (for destination data)


;EOF






Code:
;Prerequisites
;-------------
;
;- Capability to reserve physical contiguous pages to the end of the kernel.
;- Reserve an array for CR3 values (to switch contexts).
;
;
;
;Implementation
;--------------
;
;Save all general purpose registers and WIDEFLAGS
;at the start an restore at the end.
;
;Load CR3 with WIDEDI, and also save it at the first
;free WIDEWORD of the CR3 array. When initializing the
;kernel with paging, the very first element of the CR3
;array should be free, so it will also always be the
;CR3 value for the base kernel.
;
;Create 1024 entries with Not Present pages, Read/Write
;Supervisor Level, and address 0. It will then be easy to modify
;entries when allocating/freeing/setting privileges/etc.
;
;Here, what is important, is not address 0, but the Not Present
;flag. The physical address is important as it indicates strictly
;which page will become free, so we will probably need a pointer
;to an empty page in the kernel as a NULL pointer when allocating/freeing
;so we can automatically validate unequivocally which pages are truly free
;or allocated, to have a value known to the kernel against which to check
;such free (non-allocated) pages.
;
;-----------------------
;Implementation Complete
;
;
;
;Inputs:
;       WIDEDI -- 4KB-aligned memory address
;                 to place the generated page directory.
;
;;
OPCODE__CPU_generate_4KB_empty_page_directory:
push wideax
push widecx
push widesi
push widedi
pushfwide

;Load the page directory into CR3
;and store the kernel page directory
;in element 0 of the system's CR3 values array:
;;
  mov cr3,widedi

  ;Inputs:
  ;       WIDESI -- WIDEWORD array base address
  ;       WIDECX -- Number of elements
  ;
  ;
  ;Outputs:
  ;       WIDEAX -- Address of first free WIDEWORD
  ;
  ;;
  ;Store the kernel page directory
  ;in element 0 of the system's CR3 values array:
  ;;
   mov widesi,CR3_array
   mov widecx,128
   call OPCODE__binary_data__find_first_free_WIDEWORD
   mov [wideax],widedi



;Create 1024 entries with Not Present pages, Read/Write and Supervisor Level:
;;
  mov wideax,_FLAG_x86_32_pageDirectoryEntry_Bit0_Present_FALSE|_FLAG_x86_32_pageDirectoryEntry_Bit1_ReadWrite|_FLAG_x86_32_pageDirectoryEntry_Bit2_SupervisorLevel
  mov widecx,1024
  rep stosd




popfwide
pop widedi
pop widesi
pop widecx
pop wideax
retwide
db 'aaaa'






Code:
;
;;
;;;
;;;;
align wideword_sz
OPCODE__CPU_Enable_Default_Paging:
push wideax
pushfwide


;Enable paging bit 31 in CR0.
;Bit 31 for paging makes thing as if
;paging was the best, most difficult
;thing from the x86 CPU, the last thing left
;that was done:
;;
  mov eax,cr0
  or eax,10000000_00000000_00000000_00000000b
  mov cr0,eax


popfwide
pop wideax
retwide
db 'aaaa'



Attachments:
File comment: NASM Header to make assembly source code portable across 16/32/64 bits.
00000000__x86_Portable.asm [10.12 KiB]
Downloaded 11 times

_________________
Live PC 1: Image Live PC 2: Image

YouTube:
http://youtube.com/@AltComp126/streams
http://youtube.com/@proyectos/streams

http://master.dl.sourceforge.net/projec ... 7z?viasf=1
Top
 Profile  
 
 Post subject: Re: Fix triple fault reboot for this paging code
PostPosted: Mon Apr 15, 2019 1:37 pm 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
I'm not sure that you can make paging code portable across 16-, 32- and 64-bit modes as the relevant structures are either non-existant or different. Your non-standard syntax, IMO, here is confusing rather than useful. The same probably holds for most low-level code; it just doesn't make sense to speak of code being portable in this way.

But I'm glad that you solved your problem.


Top
 Profile  
 
 Post subject: Re: Fix triple fault reboot for this paging code
PostPosted: Mon Apr 15, 2019 2:16 pm 
Offline
Member
Member

Joined: Wed Mar 09, 2011 3:55 am
Posts: 509
iansjack wrote:
I'm not sure that you can make paging code portable across 16-, 32- and 64-bit modes as the relevant structures are either non-existant or different.


Not so, long mode can use 16-bit segments (the only problem being that they have the same offset/limit restrictions as otherwise pertain in long mode, so you have a 64kB flat address space when using 16-bit segments), and PAE and 64-bit paging are agnostic to the segment size being used.


Top
 Profile  
 
 Post subject: Re: Fix triple fault reboot for this paging code
PostPosted: Sat Apr 27, 2019 5:32 am 
Offline
Member
Member

Joined: Sun Apr 21, 2019 7:39 am
Posts: 76
Side note: what is WIDE?? (where ?? is the register)

_________________
Hey! I'm developing two operating systems:

NanoShell --- A 32-bit operating system whose GUI takes inspiration from Windows 9x and early UNIX desktop managers.
Boron --- A portable SMP operating system taking inspiration from the design of the Windows NT kernel.


Top
 Profile  
 
 Post subject: Re: Fix triple fault reboot for this paging code
PostPosted: Fri Oct 18, 2019 6:44 am 
Offline
Member
Member
User avatar

Joined: Tue Mar 06, 2007 11:17 am
Posts: 1225
iProgramInCpp wrote:
Side note: what is WIDE?? (where ?? is the register)
WIDECX, for example, is 16, 32 or 64-bit in size according to the mode it was compiled for, without having to modify the code.

As you can expect, the right usage of automatically-sized registers, instructions and data types can make your code fully portable across all CPU modes without modification, very similar to C.
I don't know why that automatic register size capability native to the CPU is never added to NASM or the like given the huge added portability to assembly code.

If you have used HIEW/HIEW32 (hex editor) you see that you can switch between 16/32/64-bit mode with Ctrl+F1. There are also WIDE?? instructions that adjust according to the mode (like iretwide) or pushawide (that expands to individual functions in 64-bit mode).

The register from an instruction is expanded just like the CPU does for each mode.

But you need to write a macro file or rewrite NASM/etc. to use that CPU feature (I call it x86 Portable).

See the attachment here for how to include it:
viewtopic.php?f=13&t=35245

Code:
;1632 is 386 16-bit mode, 16 is 8088/8086 16-bit mode
;;

%ixdefine _x86_Portable__PLATFORMBITS_ 1632  ;16 is the best mode for 16-bit 386+
%include "x86.asm"                           ;as it's truly specific to the size
                                             ;we will use in any mode but also
                                             ;lets us use the automatically-sized
                                             ;registers.


_________________
Live PC 1: Image Live PC 2: Image

YouTube:
http://youtube.com/@AltComp126/streams
http://youtube.com/@proyectos/streams

http://master.dl.sourceforge.net/projec ... 7z?viasf=1


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 59 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group