0

My project is to execute my own JVM on a little piece of kernel that i'm trying to code in C and assembly. So, I'm still learning how do the kernels do their main jobs.

Now, following some guides, I set up the paging

.map 
    mov         eax     , p3_t
    or          eax     , 0b11
    mov dword   [p4_t]  , eax
    mov         eax     , p2_t
    or          eax     , 0b11
    mov dword   [p3_t]  , eax

    mov        ecx      , 0
.map_pd:
    mov        eax, 0x200000
    mul        ecx
    or         eax , 0b10000011
    mov        [p2_t+ecx*8] , eax
    inc        ecx
    cmp        ecx, 512
    jne        .map_pd

    mov        eax, p4_t
    mov        cr3, eax
    mov        eax, cr4
    or         eax, 1 << 5
    mov        cr4, eax

    mov        ecx, 0xC0000080
    rdmsr
    or         eax, 1 << 8
    wrmsr

    mov        eax, cr0
    or         eax, 1 << 31
    or         eax , 1 << 16
    mov        cr0, eax

That should set up and enable paging. These guides unfortunately give me little information.

Now, how do I manage paging and virtual addresses in the C kernel? Could you guys maybe give me some other guides that talks about paging?

Frank Soll
  • 420
  • 1
  • 4
  • 15
  • 4
    Do you even require sophisticated paging, are you going to have multiple processes, virtual memory and such? Otherwise just map the whole physical memory and be done with it. – Jester Nov 08 '19 at 16:37
  • Why do you have so much space in your instructions? That makes them really hard to read (for me, at least). – 1201ProgramAlarm Nov 08 '19 at 17:53
  • @Jester for the moment I only need basic paging to load the JVM that will be the first process.Then i'll try upgrading memory management using Java. – Frank Soll Nov 08 '19 at 19:19
  • @1201ProgramAlarm going to edit it :) – Frank Soll Nov 08 '19 at 19:23
  • Good asm style is to indent your operands to a consistent column, far enough to the right of mnemonics so they're not ragged, but not *too* far (e.g. [this codereview answer](https://codereview.stackexchange.com/questions/204902/checking-if-a-number-is-prime-in-nasm-win64-assembly/204965#204965)). (Treat `dword` as part of the operand). This is an improvement in some ways (no longer too far), but now you've removed too much indenting from some. Maybe you were using tabs instead of spaces for some of them? Stack Overflow eats those; you can see from looking at your question that it's messy. – Peter Cordes Nov 09 '19 at 11:36
  • Nice edit, that's much more readable. I wouldn't put a blank line between cmp and jne, though. It makes the loop super weird. Also, you don't need `mul` here; you're not using the EDX high-half result so you could use `imul eax, ecx`. Or better, you can strength-reduce that to `add eax, 0x200000`, then you don't have to redo the `or` inside the loop. And you can optimize away `ecx` and just use `cmp eax, something` / `jb` as your loop condition. Or I guess you still need a pointer output, so nvm. – Peter Cordes Nov 09 '19 at 15:44

2 Answers2

3

It sounds like you're only enabling paging because x86-64 requires it, and you don't really want to use it for anything like giving different processes their own virtual address space:

One simple choice is to identity map all of the RAM: physical = virtual address. https://wiki.osdev.org/Setting_Up_Long_Mode#Setting_up_the_Paging

See also https://wiki.osdev.org/Paging and https://wiki.osdev.org/Setting_Up_Paging_With_PAE (the x86-64 page-table entry format is the same as 32-bit PAE, but uses more levels.)

1GB hugepages give better performance (fewer TLB misses, and shorter page-walks when you do TLB miss) and mean fewer levels of page tables and fewer total PTEs you have to set up. On older hardware 2MB hugepages might have been a good choice, but modern CPUs have good TLB support for 1G pages as well.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Sorry, but what if I want to assign an huge page to a process. Can I assign the page to multiple processes? Because otherwise if I have a little process I would have a lot of wasted memory. That's unclear to me... – Frank Soll Nov 08 '19 at 19:30
  • 1
    @FrankSoll: Oh, so you do want separate processes each to have their own virtual address space. Sure, you can do that *as well as* having the kernel map all the RAM. It's fine for a physical page to be accessible by the kernel at some virtual address as long as you don't *actually* use it for anything in the kernel while user-space "owns" that page. And yes you'd normally use 4k pages if you want to do memory protection. Your kernel's `kmalloc` or whatever you call it should keep track of which memory you're actually using. – Peter Cordes Nov 08 '19 at 19:37
  • 1
    @FrankSoll: e.g. Linux direct-maps all of physical RAM to a contiguous range of kernel virtual addresses using hugepages, but *also* maps pages of user-space virtual address space to physical pages on an as-needed basis, according to user-space `mmap` and other allocations. See https://wiki.osdev.org/Higher_Half_Kernel and see https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt for details on what Linux does. – Peter Cordes Nov 08 '19 at 19:39
2

One problem I see in your source is that you implicitly assume virtual and physical addresses are the same. For example, you link your kernel to run at 0x1000000, and copy into memory at 0x1000000. There is a certain elegance to making it relocatable, perhaps with alignment restrictions.

Your V=P assumption is shown by these instructions:

mov         eax     , p3_t
or          eax     , 0b11
mov dword   [p4_t]  , eax

If you were writing to V != P, you would have to adjust the labels p3_t, p4_t by the difference between the link & runtime address. Often people like to use %ebx for this; assuming you are using 0-based segments:

    call l1          ; get actual ip.
l1:
    pop ebx
    sub ebx, offset l1 ; adjust symbols by P - V.
...
    mov eax, pl_t[ebx]
mevets
  • 10,070
  • 1
  • 21
  • 33
  • Or in 64-bit code, of course RIP-relative addressing makes this much easier. `mov eax, [rel pl_t]` is the NASM syntax for this. Note that the 32-bit PIC code shown in the question is GAS `.intel_syntax`, not NASM. But yes, that idea. – Peter Cordes Nov 26 '19 at 19:12