Page 1 of 1

Mapping Base Address

Posted: Mon Oct 06, 2008 12:52 am
by whiteOS
Hi. For several months now I have been enjoying reading through all your very helpful posts about paging and I found a tutorial by a member here named JamesM and because of his guide I was able to implement paging in my OS. I am now trying to use it to map a memory address given to me by a base address. Here is what I have tried:

Code: Select all

#define GET_PAGE_NUMBER( address ) ( address >> 12 )
void map_mem(unsigned int base, unsigned int length)
{
	page_t *pg;
	
	//create pd
	kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
    memset(kernel_directory, 0, sizeof(page_directory_t));
   
    int i = 0;
	//create pages
    for (i = base; i < base+length; i += 0x1000)
        get_page(i, 1, kernel_directory);

	//identity map
    i = 0;
    while (i < base+0x1000)
    {
        // Kernel code is readable but not writeable from userspace.
        alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
        i += 0x1000;
    }

    // Now allocate those pages we mapped earlier.
    for (i = base; i < base+length; i += 0x1000)
        alloc_frame( get_page(i, 1, kernel_directory), 0, 0);

	//set frame to base addr
	pg->frame=GET_PAGE_NUMBER(base);
}
When I call this function:

Code: Select all

kprint("page_addr: 0x%x", map_mem(BAR5, BAR5Sze));
My OS crashes and the system reboots. What am I doing wrong and how can I fix it?

Helpful Info:
- The base address denotes a memory space address for a PCI device
- This was an honest attempt to map that address for access to the device registers
- My intent was to identity map a set of pages starting at phy_addr=base to base length, to set them for use, and then to set the frame address to the phy_addr (true base addr) for device register access

Please let me know if you need more information.

Re: Mapping Base Address

Posted: Mon Oct 06, 2008 2:14 am
by Combuster
You're going to allocate memory when you actually want to map some MMIO range. That function doesn't do that.

Re: Mapping Base Address

Posted: Mon Oct 06, 2008 11:55 am
by whiteOS
Yes, that is what I am trying to do and if that isn't how to do it then I must admit that I am at a loss here. Can someone please help to get started doing this as I at this point have no idea now what to do.

Re: Mapping Base Address

Posted: Tue Oct 07, 2008 1:08 am
by whiteOS
After a lot of effort my latest attempt is:

Code: Select all

#define secPerTrk 0x3F //= 63
#define maxHeadNm 0xFE //= 254
#define intATACmd 0x91 //= initialize ata command

//map io and tfrx
volatile unsigned int *ba0 = (void *)BAR0;
volatile unsigned int *tfr0  = (void *)BAR0+0x00;
volatile unsigned int *tfr1  = (void *)BAR0+0x04;
volatile unsigned int *tfrc  = (void *)BAR0+0x04;

unsigned int res0;
unsigned int res1;
unsigned int res2;

//write 0x003f'0000 to bits 23:16 @ bar0+0x00
*tfr0 = (*ba0&0xFF00FFFF) + (secPerTrk<<16);
//write 0x00fe'0000 to bits 23:16 @ bar0+0x04
*tfr1 = (*ba0&0xFF00FFFF) + (maxHeadNm<<16);
//write 0x9100'0000 to bits 31:24 @ bar0+0x04
*tfrc = (*ba0&0x00FFFFFF) + (intATACmd<<24);

//shift and mask written value
res0 = (*tfr0>>16) & 0xff;
res1 = (*tfr1>>16) & 0xff;
res2 = (*tfrc>>24) & 0xff;

//poll status
unsigned int status = (*tfrc>>24) & 0xff;
while(!(status & 0x80) == 0)
{
	kprint("Busy Status: 0x%x\n\nSectors Per Track: 0x%x, Max. Heads: 0x%x, ATA Cmd: 0x%x", status, res0, res1, res2);
}

//ready
kprint("READY!");
I am finally writing values and reading them back, but I dont think it works becasue it hung on the while loop. It shouldnt take long to assert so I must be doing something wrong. Can someone please look at my code and tell me what I am doing wrong?

Re: Mapping Base Address

Posted: Tue Oct 07, 2008 2:10 am
by Combuster
can status even change within the while loop? (hint)

Re: Mapping Base Address

Posted: Tue Oct 07, 2008 2:36 am
by AJ
In addition to Combuster's hint, when you do change the loop to poll correctly as he suggests, remember the use of the volatile keyword as the data pointed to by tfrc changes externally from the program (i.e. the compiler has no way of knowing *tfrc can change and may therefore optimise away the actual polling bit).

Cheers,
Adam

Re: Mapping Base Address

Posted: Tue Oct 07, 2008 1:44 pm
by whiteOS
so I changed it to this:

Code: Select all

#define secPerTrk 0x3F //= 63
#define maxHeadNm 0xFE //= 254
#define intATACmd 0x91 //= initialize ata command

//map io and tfrx
volatile unsigned int *ba0 = (void *)BAR0;
unsigned int *tfr0  = (void *)BAR0+0x00;
unsigned int *tfr1  = (void *)BAR0+0x04;
unsigned int *tfrc  = (void *)BAR0+0x04;

unsigned int res0;
unsigned int res1;
unsigned int res2;

//write 0x003f'0000 to bits 23:16 @ bar0+0x00
*tfr0 = (*ba0&0xFF00FFFF) + (secPerTrk<<16);
//write 0x00fe'0000 to bits 23:16 @ bar0+0x04
*tfr1 = (*ba0&0xFF00FFFF) + (maxHeadNm<<16);
//write 0x9100'0000 to bits 31:24 @ bar0+0x04
*tfrc = (*ba0&0x00FFFFFF) + (intATACmd<<24);

//shift and mask written value
res0 = (*tfr0>>16) & 0xff;
res1 = (*tfr1>>16) & 0xff;
res2 = (*tfrc>>24) & 0xff;

//poll status
unsigned int status = (*tfrc>>24) & 0xff;
while(!((inb(status) & 0x80) == 0));

//ready
kprint("Device Initialized!");
I think that I satisfied all of the above suggestions and it appears ti be working. but how can i be sure it is working and does any portion of my code look suspect?

Re: Mapping Base Address

Posted: Thu Oct 09, 2008 8:32 pm
by whiteOS
well, I feel like an idiot. obviously the above wont work, so I tried:

Code: Select all

unsigned int status0 = (*tfrc1>>24) & 0xff;
	while(!((status0 & 0x80) == 0));
	status0 = (*tfrc1>>24) & 0xff;

and this wont either becuase it just hangs. can someone help me?

Re: Mapping Base Address

Posted: Fri Oct 10, 2008 1:28 am
by Combuster
AJ wrote:volatile

Re: Mapping Base Address

Posted: Fri Oct 10, 2008 9:03 am
by whiteOS
I tried that too, but it still stay the same. i think device just is not responsive to my initilization commands. otherwise should what i am doing now work?

Re: Mapping Base Address

Posted: Sat Oct 11, 2008 4:11 pm
by Combuster
Well your code doesn't even do what the comments say it should...

Re: Mapping Base Address

Posted: Sat Oct 11, 2008 5:41 pm
by whiteOS
I know, it should be using the (BARx & 0xFFFFFF00)+offset as an I/O port, which I have found out from the pci 2.2 specs. also I am not mapping a memio any longer, I decided to try and access my device registers via inb and outb using the above address as the I/O port. I only return 0xFFFFFFFF, even after a write. I am quite confused as to how I should approach this.

Is it not enough to simply access the device registers using inl and outl (both dword inline asm functions) on a PC? My base address ends in 1 so I know it is I/O and I should be able to use that address as a port, correct?

for example:

outl((base0&0xFFFFFF00)+0x04)&0xFF00FFFF,0x3F);
i=inl((base0&0xFFFFFF00)+0x04));

the expected return should be 0x3F, but it is not. should I be using structs to map the base address into I/O space for access via outl and inl, or would I still map the address using a struct into I/O space so that I can manipulate the device registers using pointers, shifts, and masks? OR, should I be able to manipulate the device registers using simple outl and inl without mapping anything?

Re: Mapping Base Address

Posted: Sat Oct 11, 2008 8:30 pm
by whiteOS
Right, so I discovered that I can write directly to the device registers if I use inb and outb. if I use outl or inl then the device responds with 0xFFFFFFFF. i am not sure why this is happens sense I was sure that the deivce offered byte,word, and dword appraoches for i/o access. you see i must access the element by port i/o address so if I want bar 0 reg 1 then i must use base+0x04 as the port, but i read and write only 8 bit at a time because i forced to use inb and outb, so i must shift and mask the port address to access a certain bit field like 31:24 for example. this approach appears to be the way. this leaves me with a question --

how do i access a 8 bit bitfield from the i/o address+offset? so, for example I need to access:

let base=9800 and offset=0x04, and bitfield 23:16.

i am reading and writing to these registers using a outb and inb (byte i/o) function (which I must do), how would I access bitfield 23:16, such that --

x is written to the bitfield 23:16 of base+offset i/o address. this address contains four 8 bit wide registers for a total of 32 bits. tfyh