This question refers to an architecture using segmentation with paging. In this architecture, the 32-bit virtual address is divided into fields as follows:
4 bit segment number | 12 bit page number |
16 bit offset
Find the physical address corresponding to each of the following virtual addresses (answer "bad virtual address" if the virtual address is invalid).
1.00000000
2.20022002
3.10015555
Please help me with this, i dont know how to create page table and segment table for this mapping !!!
You are a little shy on details, so lets fill in a few:
Each segment has a 4096 (=2^12) entry translation table associated with it; otherwise it would not be interesting.
Each entry will contain a physical base address.
The extra offset will be added to this base address to find the final one.
So, in this hypothetical MMU, we could have a function like:
paddr_t translate(uint32_t vaddr) {
return segment[vaddr>>28].page[(vaddr>>16)&0xfff] + (vaddr & 0xffff);
}
A real (useful) mmu would have a bit more like:
paddr_t translate(uint32_t vaddr) {
seg_t *seg;
page_t *page;
if ((seg = segment[vaddr>>28]) && (page = seg->pagetab[(vaddr>>16)&0xfff])) {
return page->base + (vaddr & 0xffff);
} else {
raise(SEGV);
}
}
this is showing the sparseness of both segments and page mappings. It would likely have some permissions, as well, but this should help get you to the next obstacle.
Related
I'm trying to loop through all pages for a process in xv6.
I've looked at this diagram to understand how it works:
but my code is getting:
unexpected trap 14 from cpu 0 eip 801045ff (cr2=0xdfbb000)
Code:
pde_t * physPgDir = (void *)V2P(p->pgdir);
int c = 0;
for(unsigned int i =0; i<NPDENTRIES;i++){
pde_t * pde = &physPgDir[i];
if(*pde & PTE_P){//page directory valid entry
int pde_ppn = (int)((PTE_ADDR(*pde)) >> PTXSHIFT);
pte_t * physPgtab = (void *)(PTE_ADDR(*pde));//grab 20 MSB for inner page table phys pointer;
// go through inner page table
for(unsigned int j =0;j<NPDENTRIES;j++){
pte_t * pte = &physPgtab[j];
if(*pte & PTE_P){//valid entry
c++;
unsigned int pte_ppn = (PTE_ADDR(*pte)) >> PTXSHIFT;//grab 20 MSB for inner page table phys pointer;
//do thing
}
}
}
}
This is in some custom function in proc.c that gets called elsewhere. p is a process pointer.
As far as I understand, cr3 contains the physical address of the current process. However in my case I need to get the page table for a given process pointer. The xv6 code seems to load V2P(p->pgdir) in cr3. That is why I tried to get V2P(p->pgdir). However,the trap happens before pde is dereferenced. Which means there is a problem there. Am I not supposed to use the physical address?
Edit: As Brendan answered, the virtual address p->pgdir is what should be dereferenced. Additionally, the PPN from the Page directory should also be converted via P2V to properly dereference into the page table.
If someone else also gets confused about this aspect of xv6 in the future, I hope that helps.
When dealing with paging the golden rule is "never store physical addresses in any kind of pointer". The reasons are:
a) They aren't virtual addresses and can't be dereferenced, so it's better to make bugs obvious by ensuring you get compile time errors if you try to use a physical address as a pointer.
b) In some cases physical addresses are a different size to virtual addresses (e.g. "PAE paging" in 80x86 where virtual addresses are still 32-bit but physical addresses are potentially up to 52 bits); and it's better (for portability - e.g. so that PAE support can be added to XV6 easier at some point).
With this in mind your first line of code is an obvious bug (it breaks the "golden rule"). It should either be pde_t physPgDir = V2P(p->pgdir); or pde_t * pgDir = p->pgdir;. I'll let you figure out which (as I suspect it's homework, and I'm confident that by adhering to the "golden rule" you'll solve your own problem).
Using a PCAN VIEW, I determined the "rudder position" address (Yamaha Outboard), to be 166792448, and using CAN_Rx_MessageProc_ST_0 got the outboard position from bytes 4 and 5 of the 8 byte array:
RUDDER_ANGLE_RAW := WORD_TO_INT((256*MESSAGE_RX_NMEA[5]) + MESSAGE_RX_NMEA[4]);
I assumed that this Address would stay constant, but when the outboard changed, the address also changed - new address was 166792453. And further to this, after a power cycle, the address changed again to 166792456.
Assuming this has to do with address claiming, conflict, and the address changing.
The questions I have (and I have tried to grasp concepts but as a newby here am struggling) are thus:
1 Is there a range within in which this address will stay?
2 Can I get information out of the 8 byte received data (such as "yamaha outboard" or manufacturer specific info) that I could use to determine what the actual address is?
IF there is a range, I could write a procedure to scan the range, looking for the manufacturer ID, and thus determine the correct address.
Any help appreciated would be appreciated!
Whenever I try to write a pixel to the LFB of VESA mode, I get a page fault where the page is present and has been read. My paging implementation is from James Molloy's OS series. I've tried identity mapping the LFB as follows:
for (unsigned int i = 0xFD000000; i < 0xFE000000; i += 0x1000) {
page_t* pg = get_page(i, 1, kernel_directory);
alloc_page(pg, 1, 1);
}
These are the prototypes for those functions:
page_t* get_page(uint32_t address, int make, page_directory_t* dir);
void alloc_frame(page_t* page, int is_kernel, int is_writeable);
When paging is disabled, I'm able to write pixels to the LFB without any issues. Am I identity mapping the LFB incorrectly? Is there something else I need to do to identity map it correctly? Any suggestions?
When paging is disabled, your accessing address is the physical address. However, when paging is enabled, your accessing address is virtual, so you should first map the address region you will access to a phsyical address region. This can be implemented by the remap_pfn_range or nopage function, as introduced here.
My platform is Windows 7 (or later), and I am using Visual Studio 2010.
In an attempt to get a unique machine identifier, I was trying to retrieve the mac address and I encountered the following problem.
I am having difficulty identifying which is the primary ethernet network adapter from the list of adapters returned by GetAdapatersInfo method.
I can get a list of ethernet adapters by checking their type (it should be MIB_IF_TYPE_ETHERNET).
However, there are multiple ethernet adapters on my machine: Actual LAN adapter, Cisco created software adapter, bluetooth ethernet adapater, etc.
Depending upon how I am connected to the internet, this list keeps changing.
So, how do I know which one is the actual ethernet adapter (the one that will connect using LAN cable).
Well,
After experimenting for some time (about one month), the volume number seems to be a reliable metric for generating unique id which is persistent across reboots and which cannot be changed by the user. This id will not change unless the disk is reformatted.
The following code fetches the volume number.
int getVolumeNumber(char *volumeNumber, int capacity) {
for(int i=0; i<capacity; i++) {
volumeNumber[i] = '\0';
}
TCHAR volumeName[MAX_PATH + 1] = { 0 };
TCHAR fileSystemName[MAX_PATH + 1] = { 0 };
DWORD serialNumber = 0;
DWORD maxComponentLen = 0;
DWORD fileSystemFlags = 0;
if(GetVolumeInformation(_T("C:\\"), volumeName, ARRAYSIZE(volumeName), &serialNumber, &maxComponentLen, &fileSystemFlags, fileSystemName, ARRAYSIZE(fileSystemName)) != 0) {
sprintf(volumeNumber,"%lu",serialNumber);
return 0;
} else {
return 1;
}
}
In the above code, I am fetching the volume number of the C: drive.
"the volume number seems to be a reliable metric for generating unique id which is persistent across reboots and which cannot be changed by the user."
The last part of this statement ("cannot be changed by the user.") is not true. There are several utilities which either change or spoof the volume serial number.
See for example https://www.raymond.cc/blog/changing-or-spoofing-hard-disk-hardware-serial-number-and-volume-id/ .
Depending on your use case, you might be slightly better off using the hard disk serial number, which is provided by the HD manufacturer and cannot be changed by the user (but CAN be spoofed). It can be retrieved using the Win32_PhysicalMedia class (https://msdn.microsoft.com/en-us/library/windows/desktop/aa394346%28v=vs.85%29.aspx).
Another option might be to enumerate all ethernet adapters, sort them and compare the result - but it seems you have investigated this road.
In general, anything that could be used as a unique ID of a PC could be used for "software protection" (i.e. preventing unauthorised use of software), and it is therefore highly probable that people have tried to find ways to circumvent it.
Consider the following code snippet.
if (fork() == 0)
{
a = a + 5;
printf("%d, %d \n", a, &a);
}
else
{
a = a - 5;
printf ("%d, %d \n", a,& a);
}
AFAIK, when fork() is made, the virtual address space of parent is copied to the child and both child & parent share the same physical pages until one of them tries to modify. The moment one of the child & parent modifies a variable, the physical page of parent is copied to another page for child and the physical pages remain private.
So, here value of 'a' is different in child & parent. But when it comes for the addresses of 'a' in child & parent, the output is same. I am not able to figure out why the address remains same even if the physical pages are diffrent.
The address of a is not the actual physical address.
It is a virtual address.
The hardware/OS layer maps virtual addresses to physical addresses (invisibly to your application).
So even though the addresses have the same number they do not map to the same physical memory on your ram chip.
PS. When printing the address (ie pointer) using printf() best to use "%p"
The response is almost in your question: the physical page of a is copied (and thus not the same as in the parent process) after modifying a, but the virtual address (what's seen by your program, through &a) does not change.
In fact it would be very awkward to change the virtual address of a when assigning it a new value. Consider what happens if you had previously stored a pointer to a:
int *p = &a;
a = a - 5;
printf("%d", *p)
After the second line p would not point to a anymore, a behaviour that no programmer would expect.
The use of copy-on-write for physical pages is an optimization of the OS that is irrelevant to the behavior of your program: you can consider that the entire address space is copied when you fork.