Page 2 of 4

Re: Multitasking problem

Posted: Tue Jul 26, 2022 2:55 pm
by WinExperements
Hello this post not about multitasking, but about paging.
The problem is: if i manually fill the page table for framebuffer it's works fine, but if i use the mapping function i got #PF
My mapping function:

Code: Select all

void vmm_map(int *ptable,int phys,int virt) {
  write_serialString("I got: ");
  write_serialHex((int)ptable);
  write_serialString("\r\n");
  ptable[PAGE_TABLE_INDEX(virt)] = (phys) | 0x7;
  // update pointer
}
#GP info:

Code: Select all

Page fault at 0xfd0f0000
Detailed info: Present: 1
RW: 0
User page: 0
Fetch: 0
What i do wrong?

Re: Multitasking problem

Posted: Tue Jul 26, 2022 3:06 pm
by Octocontrabass
It's impossible to say what's wrong from just that code.

What kind of debugging have you done? Have you checked the contents of your page tables? (Try "info tlb" and "info mem" in the QEMU console.)

Re: Multitasking problem

Posted: Tue Jul 26, 2022 3:16 pm
by WinExperements
Octocontrabass wrote:It's impossible to say what's wrong from just that code.

What kind of debugging have you done? Have you checked the contents of your page tables? (Try "info tlb" and "info mem" in the QEMU console.)
Yeah i checked the content, by unknown to me reason it's no record about memory regions that i trying to map
"info tab" in bochs:

Code: Select all

0x0000000000000000-0x00000000003fffff -> 0x000000000000-0x0000003fffff
0x00000000c0000000-0x00000000c03fffff -> 0x000000100000-0x0000004fffff
Also it's how i do the mapping:

Code: Select all

int *fr = vmm_createTable(terminal_getBufferAddress());
   for (int i = terminal_getBufferAddress(); i < (terminal_getBufferAddress()+terminal_getBufferSize())+4096; i+=4096) {
    vmm_map(fr,i,i);
   }
vmm_createTable:

Code: Select all

int *vmm_createTable(int addr) {
  int entry = current_dir[PAGE_DIRECTORY_INDEX(addr)];
  int *ret = 0;
  if ((entry & 1) != 1) {
    ret = (int *)pmml_alloc(true);
    current_dir[PAGE_DIRECTORY_INDEX(addr)] = ((unsigned int)ret)| 0x7;
  }
  return ret;
}
EDIT: I edited the current_dir to kdirectory, because current_dir setted to 0, but it's not the reason i still have #PF, i checked the memory, and i have strange addresses:

Code: Select all

<bochs:4> info tab
cr3: 0x000000114000
0x0000000000000000-0x00000000003fffff -> 0x000000000000-0x0000003fffff
0x00000000c0000000-0x00000000c03fffff -> 0x000000100000-0x0000004fffff
0x00000000e03dc000-0x00000000e03dcfff -> 0x00001007e000-0x00001007efff
0x00000000e03dd000-0x00000000e03ddfff -> 0x00002007e000-0x00002007efff
0x00000000e03de000-0x00000000e03defff -> 0x00003007e000-0x00003007efff
0x00000000e03df000-0x00000000e03dffff -> 0x00004007e000-0x00004007efff
0x00000000e03e0000-0x00000000e03e0fff -> 0x00005007e000-0x00005007efff
0x00000000e03e1000-0x00000000e03e1fff -> 0x00006007e000-0x00006007efff
0x00000000e03e2000-0x00000000e03e2fff -> 0x00007007e000-0x00007007efff
0x00000000e03e3000-0x00000000e03e3fff -> 0x00008007e000-0x00008007efff
0x00000000e03e4000-0x00000000e03e4fff -> 0x00009007e000-0x00009007efff
0x00000000e03e5000-0x00000000e03e5fff -> 0x0000a007e000-0x0000a007efff
0x00000000e03e6000-0x00000000e03e6fff -> 0x0000b007e000-0x0000b007efff
0x00000000e03e7000-0x00000000e03e7fff -> 0x0000c007e000-0x0000c007efff
0x00000000e03e8000-0x00000000e03e8fff -> 0x0000d007e000-0x0000d007efff
0x00000000e03e9000-0x00000000e03e9fff -> 0x0000e007e000-0x0000e007efff
0x00000000e03ea000-0x00000000e03eafff -> 0x0000f007e000-0x0000f007efff
0x00000000e03eb000-0x00000000e03ebfff -> 0x00000007e000-0x00000007efff
0x00000000e03fc000-0x00000000e03fcfff -> 0x00001007e000-0x00001007efff
0x00000000e03fd000-0x00000000e03fdfff -> 0x00002007e000-0x00002007efff
0x00000000e03fe000-0x00000000e03fefff -> 0x00003007e000-0x00003007efff
0x00000000e03ff000-0x00000000e03fffff -> 0x00004007e000-0x00004007efff


Re: Multitasking problem

Posted: Tue Jul 26, 2022 10:22 pm
by Octocontrabass
What values did you manually place in the page tables to make it work?

What values are your paging functions placing in the page tables?

Re: Multitasking problem

Posted: Tue Jul 26, 2022 10:58 pm
by nullplan
WinExperements wrote:

Code: Select all

void vmm_map(int *ptable,int phys,int virt) {
  write_serialString("I got: ");
  write_serialHex((int)ptable);
  write_serialString("\r\n");
  ptable[PAGE_TABLE_INDEX(virt)] = (phys) | 0x7;
  // update pointer
}
That looks wrong because you have at the least two levels of page tables. Actually, with the types given here, it can only be 32-bit mode without PAE. So something closer to correct might be:

Code: Select all

void vmm_map(uint32_t *ptable, uint32_t phys, uint32_t virt) {
  ptable += virt >> 22;
  if (!(*ptable & 1))
    *ptable = page_zalloc_or_die() | 7;
  ptable = (uint32_t*)(*ptable & 0xfffff000);
  ptable[(virt >> 12) & 0x3ff] = phys | 7;
}
Still not great, but some crucial improvements: First of all, if you want all those variables to be 32-bit types, make them 32-bit types. "int" can be anything. Even better would be to make dedicated types for physical addresses, which reduces the amount of work you have to do if you ever support PAE.

I am assuming an identity paged system up there. If you do not have that, the line where we move from page directory to page table must be changed accordingly. The page directory only tells you the physical address, and how you map it such that you can access it is for you to know.

Future improvements: You may want to have this function be capable of returning error, so you don't need to panic if you are out of memory. As I said, some more specific types would be great. Maybe don't assume the attributes but get them from parameters (at least whether the actual page at the end is writable or supervisor-only ought to be in there).

Re: Multitasking problem

Posted: Wed Jul 27, 2022 1:43 am
by WinExperements
nullplan wrote:
WinExperements wrote:

Code: Select all

void vmm_map(int *ptable,int phys,int virt) {
  write_serialString("I got: ");
  write_serialHex((int)ptable);
  write_serialString("\r\n");
  ptable[PAGE_TABLE_INDEX(virt)] = (phys) | 0x7;
  // update pointer
}
That looks wrong because you have at the least two levels of page tables. Actually, with the types given here, it can only be 32-bit mode without PAE. So something closer to correct might be:

Code: Select all

void vmm_map(uint32_t *ptable, uint32_t phys, uint32_t virt) {
  ptable += virt >> 22;
  if (!(*ptable & 1))
    *ptable = page_zalloc_or_die() | 7;
  ptable = (uint32_t*)(*ptable & 0xfffff000);
  ptable[(virt >> 12) & 0x3ff] = phys | 7;
}
Still not great, but some crucial improvements: First of all, if you want all those variables to be 32-bit types, make them 32-bit types. "int" can be anything. Even better would be to make dedicated types for physical addresses, which reduces the amount of work you have to do if you ever support PAE.

I am assuming an identity paged system up there. If you do not have that, the line where we move from page directory to page table must be changed accordingly. The page directory only tells you the physical address, and how you map it such that you can access it is for you to know.

Future improvements: You may want to have this function be capable of returning error, so you don't need to panic if you are out of memory. As I said, some more specific types would be great. Maybe don't assume the attributes but get them from parameters (at least whether the actual page at the end is writable or supervisor-only ought to be in there).
I write something like you post, but still i receive the #PF, can be that i incorrectly allocated the page table?
And it's how i manually fill the page table:

Code: Select all

for (int i = terminal_getBufferAddress(); i < (terminal_getBufferAddress()+terminal_getBufferSize())+4096; i+=4096) {
    fr_pdir[PAGE_TABLE_INDEX(i)] = (i) | 7;
   }
   kdirectory[PAGE_DIRECTORY_INDEX(terminal_getBufferAddress())] = ((unsigned int)fr_pdir) | 7;
Defines and macroses used:

Code: Select all

int fr_pdir[1024] __attribute__((aligned(4096))); // framebuffer
#define PAGE_DIRECTORY_INDEX(x) (((x) >> 22) & 0x3ff)
#define PAGE_TABLE_INDEX(x) (((x) >> 12) & 0x3ff)
EDIT: If i trying to use allocated page table and use it for manual filling it shows me the #PF, it seems like problem in my page allocator or no?

Re: Multitasking problem

Posted: Wed Jul 27, 2022 2:37 am
by xeyes
One way to debug paging issues is to use this command in Qemu right after you've loaded CR3.
gva2gpa addr

Print the guest physical address at which the guest’s virtual address addr is mapped based on the mapping for the current CPU.
If it prints 'Unmapped' or unexpected physical addresses, you'd know that something is wrong with the tables.

Re: Multitasking problem

Posted: Wed Jul 27, 2022 3:12 am
by WinExperements
xeyes wrote:One way to debug paging issues is to use this command in Qemu right after you've loaded CR3.
gva2gpa addr

Print the guest physical address at which the guest’s virtual address addr is mapped based on the mapping for the current CPU.
If it prints 'Unmapped' or unexpected physical addresses, you'd know that something is wrong with the tables.
I found that if i don't use align attribute it's shows me #PF, it's works only if a add the align attribute.
And about this command it's shows me that that some addresses of framebuffer are unmapped
Do i need to add aligned allocation in my allocator?
EDIT: Yeah the problem in my table allocation, how i can do aligned allocation using page frame allocator?

Re: Multitasking problem

Posted: Wed Jul 27, 2022 10:52 am
by Octocontrabass
WinExperements wrote:EDIT: Yeah the problem in my table allocation, how i can do aligned allocation using page frame allocator?
Page frames are always aligned. If your allocator returns addresses that aren't aligned, your allocator is broken.

How does your allocator track free page frames?

Re: Multitasking problem

Posted: Wed Jul 27, 2022 11:01 am
by WinExperements
Octocontrabass wrote:
WinExperements wrote:EDIT: Yeah the problem in my table allocation, how i can do aligned allocation using page frame allocator?
Page frames are always aligned. If your allocator returns addresses that aren't aligned, your allocator is broken.

How does your allocator track free page frames?
My allocator used bitmap for tracking pages. How i can check if address aligned?
Here how allocator allocate/freeing page, maybe you can found any bug here:

Code: Select all

void *pmml_alloc(bool clear) {
	// found free block, if not panic
	uint64_t freeBlock = -1;
	for (int i = 0; i < max_blocks; i++) {
		if (!is_block_used(i)) {
			freeBlock = i;
			break;
		}
	}
	if (freeBlock == -1) {
		PANIC("Out of memory");
	}
	used_blocks++;
	set_block_used(freeBlock,true);
	void *addr = (void *)(mem_start + (freeBlock*PHYS_PAGE_SIZE));
	if (clear) {
		memset(addr,0,4096);
	}
	return addr;
}
int pmml_free(void *addr)
{
	int index = (int)(addr-mem_start)/PHYS_PAGE_SIZE;
	if (!is_block_used(index)) {
		printf("pmml_free: given address are not allocated\n");
		return false;
	}
	set_block_used(index,false);
	memset(addr,0,4096);
	if (is_block_used(index))
		PANIC("Free, bitmap set fail");
	return true;
}

Re: Multitasking problem

Posted: Wed Jul 27, 2022 11:17 am
by Octocontrabass
WinExperements wrote:My allocator used bitmap for tracking pages.
How do you calculate the page frame address from the bit location?
WinExperements wrote:How i can check if address aligned?
For 4kB alignment, the lowest 12 bits of the address are zero.

Re: Multitasking problem

Posted: Wed Jul 27, 2022 12:56 pm
by WinExperements
Octocontrabass wrote:
WinExperements wrote:My allocator used bitmap for tracking pages.
How do you calculate the page frame address from the bit location?
WinExperements wrote:How i can check if address aligned?
For 4kB alignment, the lowest 12 bits of the address are zero.
I re-check the allocation method and found that allocator return's address of reserved page, so i fixed that by marking reserved pages as used. And it's works. Thanks.

Re: Multitasking problem

Posted: Mon Aug 01, 2022 4:41 pm
by WinExperements
Hello i have new problem, when my user program trying to use syscall i got PF with address 0xff0ff, what i do wrong?
There are my user program:

Code: Select all

void module_main();
char *message = "HHELLLOOOO\n";
void _start() {
	module_main();
}
void module_main() {
	int res;
	int num = 1;
	asm volatile("int $0x80" : "=a" (res) : "0" (num), "b" ((int)message));
	for (;;) {}
}
This program starts at 0x400000

Re: Multitasking problem

Posted: Mon Aug 01, 2022 4:51 pm
by Octocontrabass
What are the CS:EIP, EFLAGS, and error code pushed on the stack by the CPU? What are the contents of the other registers upon entry to your #PF handler?

Re: Multitasking problem

Posted: Tue Aug 02, 2022 2:13 am
by WinExperements
Octocontrabass wrote:What are the CS:EIP, EFLAGS, and error code pushed on the stack by the CPU? What are the contents of the other registers upon entry to your #PF handler?
I have the QEMU log about exception:

Code: Select all

51: v=80 e=0000 i=1 cpl=3 IP=001b:00400033 pc=00400033 SP=0023:0020e3f0 env->regs[R_EAX]=00000001
EAX=00000001 EBX=00ff00ff ECX=00000000 EDX=00ff00ff
ESI=00000000 EDI=00000000 EBP=0020e3f4 ESP=0020e3f0
EIP=00400033 EFL=00000282 [--S----] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
CS =001b 00000000 ffffffff 00cffa00 DPL=3 CS32 [-R-]
SS =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
DS =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
FS =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
GS =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =002b 00111080 00000068 0000e900 DPL=3 TSS32-avl
GDT=     00111040 0000002f
IDT=     00111120 000007ff
CR0=80000011 CR2=00000000 CR3=00206000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000000 CCD=fffffffe CCO=DECL
EFER=0000000000000000
check_exception old: 0xffffffff new 0xe
    52: v=0e e=0000 i=0 cpl=0 IP=0008:001006ae pc=001006ae SP=0010:0020ef50 CR2=00ff00ff
EAX=00ff00ff EBX=00ff00ff ECX=00000000 EDX=00000020
ESI=00000000 EDI=00000000 EBP=0020ef68 ESP=0020ef50
EIP=001006ae EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =002b 00111080 00000068 0000e900 DPL=3 TSS32-avl
GDT=     00111040 0000002f
IDT=     00111120 000007ff
CR0=80000011 CR2=00ff00ff CR3=00206000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000018 CCD=0020ef50 CCO=SUBL
EFER=0000000000000000
And by there logs i can say that syscalls works fine, can that the message are unmapped?
Yeah i thing that message are unmapped because i see that address of message passed to syscall handler are the same that fault address, can be the problem in my incorrect ELF loading?
EDIT: The problem caused by the incorrect linking, and linker cannot find the entry point, i fixed that by editing entry point name in linker script.