flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Changing memory map in LONG MODE

Author
Thread Post new topic Reply to topic
Adan



Joined: 30 Mar 2007
Posts: 17
Adan 09 Sep 2008, 23:19
Hello everyone, I have a simple question about dynamically changing a mem map, the problem is:

I'm running in a long mode environment where the first 8MB of memory are mapped 1:1 when the kernel starts, but then I need (for some reason) allocate a new page frame from a page frames stack (that returns physical addresses) to use it for a new table in the paging structure (pml4, pdpt, pdt, pt), now, the question is, how do I set the needed attributes in the new allocated table before using it if it is not mapped anywhere in the kernel address space (remember it is a PHYSYCAL ADDRESS) and paging can not be disabled in long mode? I can't write anithing to that new address cause the processor doesn't 'know' it, its a high physycal RAM address.

Hope someone can help me an thanks in advance.
Post 09 Sep 2008, 23:19
View user's profile Send private message MSN Messenger Reply with quote
Feryno



Joined: 23 Mar 2005
Posts: 509
Location: Czech republic, Slovak republic
Feryno 10 Sep 2008, 14:34
it is even possible to change the virtual memory of the running kernel on-the-fly - e.g. you are at virtual memory 80000 and you want to change it to FFFFFFFF00080000 (kernel stays at the same physical memory, you just add new entries into paging tables - at this point the physical memory is mapped twice into 2 different virtual addresses - then make a long jump to new virtual address and at the end remove the old entries from paging tables)
well back to your question

you have written that you kernel is running in identity mapped memory of size 8 MB (virtual address = physical address), you know where you have PML4, PDP, PD, several PTs (no one PT if you mapped all 8 MB using 4 large pages of 2 MB)

you want to map just one 2 MB page e.g. at physical memory (RAM) 6 GB
PA = 6*1024*1024*1024
and you want to map that 2 MB physical memory page into virtual address space 8MB - 10MB
VA = 8*1024*1024
it is possible to do it in just 2 instructions in assembler !
assume you know where you have mapped your PD - at virtual address Z which is somewhere inside your 8 MB virtual memory
then do it in this way:
mov rax,PA + 10000011b ; 10000011b = bit 7 set (PD.PSE=1, that means 2 MB pages and PD is the last level), bit 1 set (writeable), bit 0 set (Present)
t = (VA shr 21) and 111111111b ; extract bits 29-21 of virtual address
mov [Z + t*8],rax
; if the PA is below 4 GB, then it is possible to do that mapping using just 1 assembler instruction !!!!!!!!!!!!!!!!!
; mov qword [Z + t*8],(PA + 10000011b)

after the last instruction, you have 2 extra MB of mapped memory, you can create additional paging tables there

e.g. you want to map 1 page of 4 kB from physical memory 7GB and you want it become the virtual address FFFFFFFF05000000h
assume your PML4 is at virtual address X somewhere inside your 8 MB kernel and its virtual address = its physical address
PA2 = 7*1024*1024*1024 ; address in RAM
VA2 = FFFFFFFF05000000h ; returned virtual address
1 empty 2 MB page is mapped at VA=8*1024*1024 and it is in physical memory PA=6*1024*1024*1024
you create 1 new PDP at the first 4 kB memory block at 6GB+0*4kB = PA, 1 new PD at the second 4 kB memory block 6GB+1*4kB = PA+1000h, 1 new PT at the third 4 kB memory block 6GB+2*4kB = PA+2000h and finally put just 1 entry (PTE) into PT

mov rax,PA + 11b ; 11b means bit 1 set (writeable), bit 0 set (present)
t = (VA2 shr 39) and 111111111b (extract bits 47-39 of virtual address)
mov [X + t*8],rax ; write PML4E into PML4 (bits 51-12 of PML4E = the pointer into physical memory base of next level which is PDP table)

mov rax,PA+1000h + 11b
t = (VA2 shr 30) and 111111111b (extract bits 38-30 of virtual address)
mov [VA + t*8],rax ; write PDPE into PDP

mov rax,PA+2000h + 11b
t = (VA2 shr 21) and 111111111b (extract bits 29-21 of virtual address)
mov [VA+1000h + t*8],rax ; write PDE into PD

mov rax,PA2 + 11b
t = (VA2 shr 12) and 111111111b (extract bits 20-12 of virtual address)
mov [VA+2000h + t*8],rax ; put PTE (PT entry) into PT

after the last instruction, new virtual address range FFFFFFFF05000000h-FFFFFFFF05000FFFh appears and when you write a byte into virtual address FFFFFFFF05000000h then the byte is written into physical address (RAM) at position PA2 = 7GB
Post 10 Sep 2008, 14:34
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20299
Location: In your JS exploiting you and your system
revolution 10 Sep 2008, 15:36
Feryno wrote:
it is even possible to change the virtual memory of the running kernel on-the-fly - e.g. you are at virtual memory 80000 and you want to change it to FFFFFFFF00080000 (kernel stays at the same physical memory, you just add new entries into paging tables - at this point the physical memory is mapped twice into 2 different virtual addresses - then make a long jump to new virtual address and at the end remove the old entries from paging tables)
And don't forget to purge the affected TLBs and caches after changing the page tables but before jumping to any area of the virtual memory map that is affected by the change.
Post 10 Sep 2008, 15:36
View user's profile Send private message Visit poster's website Reply with quote
Feryno



Joined: 23 Mar 2005
Posts: 509
Location: Czech republic, Slovak republic
Feryno 11 Sep 2008, 12:33
if you want to purge only 1 page, then use:
invlpg [address_of_page]
e.g.
lea rax,[address_anywhere_inside_of_page]
invlpg [rax]
if the address is not further than 2GB from RIP, then you can use directly invlpg [address_of_page] which is done by FASM using RIP-relative addressing invlpg [rip+-difference] (difference is limited to be signed dword, so the +- 2 GB limit comes from here)

if you want to purge all nonglobal pages, then use:
mov rax,cr3
mov cr3,rax

if you want (usually very rarely or almost never) to purge all global pages (bit 8. of entries in the last level of translation tables is set and CR4.PGE bit 7. is set), then use:
(toggling bit 7. of CR4 - CR4.PGE)
mov rax,cr4
mov rcx,rax
and al,not (1 shl 7)
mov cr4,rax ; this instruction flushes all global and nonglobal pages out of TLB (but note for Intel CPUs, manual says: works on all P4, Xeon, P6 family... and we shouldn't depend on this functionality in all Intel64 processors...)
mov cr4,rcx ; this restores cr4 back

global pages are sometimes very necessary, e.g. when your kernel switches to a new task with new CR3, the kernel must load new translation tables without losing translation of critical kernel pages (to prevent the code doing task switching from disappearing from the virtual memory translation mechanism after executing mov cr3,reg64). After loading new CR3, all nonglobal pages disappear from the virtual memory translation mechanism, only global pages stays in TLB so your kernel code is able continue its execution if the critical kernel pages doing task switching are global (code, stack, system data)

if you want to flush out of TLB only 1 global page, then use invlpg [address]
Post 11 Sep 2008, 12:33
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
Adan



Joined: 30 Mar 2007
Posts: 17
Adan 11 Sep 2008, 21:06
Is the argument of invlpg a physycal o virtual address?, could you give an example please?

Supose I want to invalidate a page frame mapped at virtual address 0x2000, how this command would be?

Thanks.
Post 11 Sep 2008, 21:06
View user's profile Send private message MSN Messenger Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20299
Location: In your JS exploiting you and your system
revolution 12 Sep 2008, 01:00
Adan: To save you having to wait for an answer to be posted here you can also check out the excellent Intel and/or AMD programmers manuals (Google them). These comprehensive documents give the details of every instruction available within the CPUs. I thoroughly recommend you download a copy for your future reference.
Post 12 Sep 2008, 01:00
View user's profile Send private message Visit poster's website Reply with quote
Feryno



Joined: 23 Mar 2005
Posts: 509
Location: Czech republic, Slovak republic
Feryno 12 Sep 2008, 19:37
invlpg uses virtual address, so do this:
mov eax,2000h
invlpg [rax]
if the mapped page has only 4 kB (in your sample it can't have 2 MB size) the same may be done using mov eax,2FFFh \ invlpg [rax]... it doesn't matter whether you invalidate the first or the last or any byte in the middle of virtual memory page, you also needn't to worry whether the page is 2 MB or 4 kB)

mapped addresses are usually stored somewhere (to unmap them later), so in that case you must do:
mov rax,qword [stored_virtual_addr]
invlpg [rax]
note that using invlpg qword [stored_virtual_addr] is wrong and a big mistake !!!

btw0 the manual doesn't say it exactly (Intel: The source operand is a memory address... AMD: Invalidate the TLB entry for the page containing a specified memory location...) so this is the reason why I did you direct answer (I hope correct, I didn't know the answer after reading manuals, so I did tests months ago when I needed that to implement in my work and the INVLPG behaved according virtual memory address, not physical). If I had used my brain more before those of experiments, I would had the same result (plus faster as a benefit) because it looks more logical, it is necessary to purge virtual address, not physical...)

btw1 instructions using physical address are very rare
mov cr3,reg64 \ mov reg64,cr3 \ mov reg64,cr2
mov rax,physical_address \ mov qword [rsp],rax \ vmxon qword [rsp] and similar instructions of virtualization
and you also use physical address when constructing virtual memory translation tables
this is almost everything usefull with physical address under long mode. There are perhaps another instructions using physical addresses but I can't remember them from my head at this night time here. If somebody knows such instruction, let post it here.

btw2 The famous manuals are very huge and split into few separate pdf files - each of size about 1-5 MB

http://developer.amd.com/documentation/guides/Pages/default.aspx
instructions are here:
http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24594.pdf

http://www.intel.com/products/processor/manuals/index.htm
instructions A-M are here:
http://download.intel.com/design/processor/manuals/253666.pdf
instructions N-Z are here:
http://download.intel.com/design/processor/manuals/253667.pdf

btw3
the intel changes manuals very frequently (the last change was after about half a year and the most of changes were just in the virtualization technology)
Post 12 Sep 2008, 19:37
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
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 vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.