Page fault when trying to access VESA LFB with paging enabled - operating-system

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.

Related

How to loop through all page table entries of a process in xv6?

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).

mapping virtual address (logical address) to physical address

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.

C++/Windows: Get unique machine id: mac address, volume serial number,

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.

how to retrieve bus pointer from device tree

Question:
I'm trying to find a way to retrieve the dev object for an mdio_bus that has been added to the device tree. I'm sure I'm going to be rapidly applying my palm to my forehead when I get past this, but for the life of me, I can't find the answer anywhere. I've seen how to find objects on the bus itself using bus_find_device_by_name(), but I can't seem to find how to get the bus itself.
Background:
We are providing network access to our host using a Micrel KSZ8863 Ethernet switch attached to the MACB on an at919g20. Rather than using the fixed PHY option, I've spoofed MDIO address 0 to be a "fake" PHY representing the fixed MII link to the switch. I'm writing a driver for the switch to receive its interrupts and monitor the outward facing PHYs and control the link state of the "fake" PHY to the host. In order to configure the switch beyond basic MIIM configuration, you need to use SMI on the MDIO bus to access the full array of registers in the switch. Through further tweaking of the mii_read/write functions in the MACB, adding a header to the reg address, I believe I can use the MACB's MDIO/MII controller to do the right thing for SMI requests. Because the bus no longer gets addressed by PHY:REG, I need to be able to issue raw read/write commands straight to the bus from the switch driver. And that brings me back to my question: How do I request the dev object of the mdio_bus from the device tree by name?
Thanks,
Brian
After hunting around, fruitlessly, for a way to retrieve a device pointer to an mii_bus object, I ended up coming up with the following solution. I'm not sure its the best way to go about it, but it seems pretty clean. I basically ended up adding a helper function to mdio_bus.c that allows another driver to search for a bus by name using class_find_device(). I'm sure there is better way to do this, that doesn't involve adding onto the bus' driver, but it doesn't seem like the worst way either.
-Brian
Here are the functions I added to mdio_bus.c:
/**
* mdiobus_match_name - compares specified string to the device name
* #dev: device object to be examined
* #data: pointer to string to compare device name to
*
* Description: matching function used in call to class_find_device() to find
* a device with the specified name
*/
static int mdiobus_match_name( struct device * dev, void * data )
{
const char * name = data;
return sysfs_streq( name, dev_name( dev ) );
}
/**
* mdiobus_find_by_name - Convenience function for retrieving an mii_bus pointer
* by name
* #name: name of the bus being searched for
*/
struct mii_bus * mdiobus_find_by_name( char * name )
{
struct device * dev;
/* search devices registered for with the mdio_bus_class using the device
name as the matching criteria */
dev = class_find_device( &mdio_bus_class,
NULL,
(void *)name,
mdiobus_match_name );
/* return the mii_bus pointer or NULL if none was found */
return dev ? container_of( dev, struct mii_bus, dev ) : NULL;
}
EXPORT_SYMBOL( mdiobus_find_by_name );

Why address of variable remain same in fork() system call after it is modified

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.