OSDev.org

The Place to Start for Operating System Developers
It is currently Wed Apr 17, 2024 9:10 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: Running code in regular memory when linked to higher-half?
PostPosted: Sat Jul 01, 2023 3:12 pm 
Offline

Joined: Sat Jun 18, 2022 11:38 pm
Posts: 16
I've been working my way through getting different address spaces working, but I've come to a point where I want to copy one physical frame to another. I am able to get the physical addresses, so now I've tried to write an assembly function that just turns off paging, copies the data, and turns it back on - but I'm running into a problem. All my labels are offset by 3GB (0xC0000000, accessible as $VIRTUAL_BASE), which I've been working around by just subtracting that value, but I've now found that i686-elf-as doesn't allow conditional jumps to addresses in registers (ex. jmp *%edx works, jz *%edx does not). Also, it doesn't allow looping to addresses in registers with the loop command, so I'm not really sure what else to do.

I tried to make a specific section that would be linked to the lower half, but only after the multiboot header, which I wasn't able to get working - so the only option I saw left was rep movsb, but I still don't think that's working properly as the function never returns to the C from which it was called, and I think just ends up running garbage somewhere in lower memory (it never gets to re-enabling paging). I believe the best option here would be to just link to the lower half, but since I couldn't get that to work, I'm not sure what to do. Does anyone know how to make one specific section link normally without the virtual memory offset (and force it to come after the mulriboot header), or have any other way to copy one section of memory to another?

Here is what I've made so far:
Code:
.global copy_page_physical
copy_page_physical:
   pushl %eax
   pushfl
   cli

   # get the source and destination addresses, as pushed from C
   movl 12(%esp), %esi
   movl 16(%esp), %edi

   lea (lower_half_cpp), %edx
   subl $VIRTUAL_BASE, %edx

   # disable paging
   movl %cr0, %ecx
   andl $0x7FFFFFFF, %ecx
   movl %ecx, %cr0
   # we shouldn't need to move the stack, unless we need to pop something before re-enabling paging

   jmp *%edx

lower_half_cpp: # "lower half CopyPagePhysical"
   # movsb needs the number of bytes to copy in ecx, so since we're not storing anything necessary there, that works out
   movl $1024, %ecx
   rep movsb

   # re-enable paging
   lea (higher_half_cpp), %edx

   movl %cr0, %eax
   orl $0x80000000, %eax
   movl %eax, %cr0

   jmp *%edx

higher_half_cpp:

   # magic breakpoint, which *is* triggered, somehow?
   xchgw %bx, %bx

   popfl
   popl %eax
   sti
   ret #either jumps to nonsense, or is never reached


And the linkerfile, since we're dealing with virtual memory:
Code:
/* The bootloader will look at this image and start execution at the symbol
   designated as the entry point. */
ENTRY(_start)

/* A few definitions the assembly code can use for physical addresses. */
PHYSICAL_BASE = 0x00100000;
VIRTUAL_BASE = 0xC0000000;

SECTIONS
{

   /* Begin putting sections at 1 MiB, a conventional place for kernels to be
      loaded at by the bootloader, and add C0000000 (3GB) for paging. */
   . = 0xC0100000;

   /* Multiboot comes first for GRUB to find, then stack*/
   .text ALIGN (0x1000) : AT(ADDR(.text)-0xC0000000)
   {
      *(.multiboot*)
      *(.text*)
   }

   /* Read-only data. */
   .rodata ALIGN (0x1000) : AT(ADDR(.rodata)-0xC0000000)
   {
      *(.rodata*)
   }

   /* Read-write data (initialized) */
   .data ALIGN (0x1000) : AT(ADDR(.data)-0xC0000000)
   {
      *(.data*)
   }

   /* Read-write data (uninitialized) and stack */
   .bss ALIGN (0x1000) : AT(ADDR(.bss)-0xC0000000)
   {
      *(COMMON*)
      *(.bss*)
   }

   KERNEL_END = .;
}


Top
 Profile  
 
 Post subject: Re: Running code in regular memory when linked to higher-hal
PostPosted: Sat Jul 01, 2023 4:06 pm 
Online
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5137
minater247 wrote:
Does anyone [...] have any other way to copy one section of memory to another?

Don't turn off paging. Update your page tables to map both regions of memory, if they're not both already mapped. Copy your data. Update your page tables again to unmap any memory you no longer want to have mapped.

Do you need to copy anything in the first place? Paging allows you to map the data at your choice of virtual address.


Top
 Profile  
 
 Post subject: Re: Running code in regular memory when linked to higher-hal
PostPosted: Sat Jul 01, 2023 4:07 pm 
Offline
Member
Member

Joined: Sat Nov 21, 2009 5:11 pm
Posts: 852
Quote:
which I've been working around by just subtracting that value, but I've now found that i686-elf-as doesn't allow conditional jumps to addresses in registers

That's because those instructions don't exist. What's wrong with simply "jmp lower_half_cpp-$VIRTUAL_BASE"?

As for why it crashes, it's because you turned off paging while EIP still points to a high address. Instead of doing this dance every time you want to copy a page, you should probably just map the new page somewhere.


Top
 Profile  
 
 Post subject: Re: Running code in regular memory when linked to higher-hal
PostPosted: Sat Jul 01, 2023 5:09 pm 
Offline

Joined: Sat Jun 18, 2022 11:38 pm
Posts: 16
Quote:
Don't turn off paging. Update your page tables to map both regions of memory, if they're not both already mapped.


I guess that makes sense too! I had thought it would be easier to just write a snippet of assembly like any other non-paged program would, but just setting up a couple of reserved frames for this purpose could work too.

Quote:
Do you need to copy anything in the first place?


I had thought cloning address spaces requires copying any non-kernel pages? All the kernel entries I just map to their original places, but I copy everything else to make sure two processes don't collide in memory. Is this not what you're supposed to do?

Quote:
What's wrong with simply "jmp lower_half_cpp-$VIRTUAL_BASE"?

I was just using that as an example - a better one might be:
Code:
movl $1024, %ecx
lower_half_cpp_loop:
   movb (%esi), %edx
   movb %edx, (%edi)
   incl %edi
   incl %esi
   decl %ecx
   jnz lower_half_cpp_loop

Where I'd tried doing as I had been, since the physical address was in edx:
Code:
jnz *%edx

Which, apparently, doesn't exist. Not exactly sure if jnz or any other conditional jump works with the syntax you showed - not at the same computer right now but I'll check later. First I'll try just using paging to map those addresses elsewhere.


So I guess this whole bit was a tad useless, then - I wonder why the instruction set lets that syntax work, but only for plain jmp commands... who knows. Thanks for all the help, I'll go give this a shot when I get back home!


Top
 Profile  
 
 Post subject: Re: Running code in regular memory when linked to higher-hal
PostPosted: Sat Jul 01, 2023 6:45 pm 
Online
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5137
minater247 wrote:
I had thought cloning address spaces requires copying any non-kernel pages?

Only if those pages need to contain different data.

minater247 wrote:
All the kernel entries I just map to their original places, but I copy everything else to make sure two processes don't collide in memory. Is this not what you're supposed to do?

That's one way to do it.

Another way is to make the pages read-only and copy them when the new process causes a #PF trying to write to them (copy-on-write). Make sure you set CR0.WP appropriately for your implementation. On Unix-like OSes, where calls to fork() are usually followed by calls to exec(), this is a big optimization.

minater247 wrote:
So I guess this whole bit was a tad useless, then - I wonder why the instruction set lets that syntax work, but only for plain jmp commands...

Only Intel could tell you that. I suggest you refer to the Intel (or AMD) manuals if you want to know which instructions support which address modes.


Top
 Profile  
 
 Post subject: Re: Running code in regular memory when linked to higher-hal
PostPosted: Sat Jul 01, 2023 7:20 pm 
Offline

Joined: Sat Jun 18, 2022 11:38 pm
Posts: 16
That did it, it can now copy data from physical frames! Although I was noticing it was too slow for actual use, that sounds like a really good way to tell if they need to access the data there, I'll implement that once I get kernel/non-kernel program interaction working properly, thanks for showing me that! And I'd been using an online reference that bunched them together (the manual takes ages to load on my computer), so it appears the actual manual serves as a better reference, so I'll go there from now on. Anyways, thank you so much for the help!


Top
 Profile  
 
 Post subject: Re: Running code in regular memory when linked to higher-hal
PostPosted: Sun Jul 02, 2023 5:21 am 
Offline
Member
Member

Joined: Sat Nov 21, 2009 5:11 pm
Posts: 852
Quote:
Not exactly sure if jnz or any other conditional jump works with the syntax you showed

Direct near jump instructions are relative, so there is nothing to add or subtract in this case. I highly suggest learning the basic IA-32 instruction set before starting on an operating system instead of guessing. I think the individual volumes of the Intel programmer's manual are available as separate files, so you don't have to load the entire thing.


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 89 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