0

The OS Dosent display the upper and lower memory for some reason. As you can see here in Detecting Memory Wiki : http://wiki.osdev.org/Detecting_Memory_(x86)#Memory_Map_Via_GRUB , it says

Refer to mbd->mem_lower for conventional memory (e.g. physical addresses ranging between 0 and 640KB) and mbd->mem_upper for high memory (e.g. from 1MB). Both are given in kibibytes

Well i am exactly doing so here:

kernel.c++ :

#include "types.h"
#include "gdt.h"
#include "stdio.h"
#include "serial.h"
#include "mem.h"
#include "idt.h"
#include "timer.h"
#include "isr.h"
#include "kbd.h"
#include "mouse.h"
#include "irq.h"
#include "string.h"
#include "terminal.h"
#include "multiboot.h"
#include "pmm.h"
#include "heap.h"




//Call all class constructor
//for global objects before
//calling the kernel
typedef void (*constructor)();
extern "C" constructor start_ctors;
extern "C" constructor end_ctors;
extern "C" void callConstructors()
{
    for(constructor* i = &start_ctors; i != &end_ctors; i++)
       (*i)();
}




extern "C" void kernelMain(uint32_t kernel_virtual_end,
        uint32_t placeholder,
        uint32_t  kernel_physical_end,
        uint32_t kernel_physical_start, uint32_t  kernel_virtual_start,
        multiboot_info_t multiboot_structure,uint32_t magicnumber
        )
{


       cls();
       printf("******KERNEL INFO********\n");
       printf("KERNEL START VIRTUAL 0x%x\n" , kernel_virtual_start);
       printf("KERNEL START PHYSICAL 0x%x\n" , kernel_physical_start);
       printf("KERNEL END VIRTUAL 0x%x\n" , kernel_virtual_end);
       printf("KERNEL END PHYSICAL 0x%x\n" , kernel_physical_end);
       printf("*************************\n\n");
       printf("********RAM INFO*********\n");
       printf("LOWER MEMORY : %x \n" , (uint32_t)multiboot_structure.mem_lower);
       printf("UPPER MEMORY : %x \n" , (uint32_t)multiboot_structure.mem_upper);
       printf("*************************\n");
       gdt gt;
       IDT idt;
       ISR isr;
       IRQ irq;
       SerialPort sp;
       isr.install_isrs();
       irq.install_irqs();
        Timer timer;
        timer.install_timer();
        KBD kbd;
        kbd.install_kbd_driver();


        MOUSE mouse;
        mouse.install_mouse_driver();
        __asm__ __volatile__ ("sti");




   while(1);
   err:
       while(1);
}

boot.asm:

;Global MultiBoot Kernel Recongnzatio

; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ  1<<0             ; align loaded modules on page boundaries
MEMINFO     equ  1<<1             ; provide memory map
FLAGS       equ  MODULEALIGN | MEMINFO  ; this is the Multiboot 'flag' field
MAGIC       equ    0x1BADB002     ; 'magic number' lets bootloader find the header
CHECKSUM    equ -(MAGIC + FLAGS)  ; checksum required


;Putting in object file
section .multiboot

    dd MAGIC
    dd FLAGS
    dd CHECKSUM

section .data

KERNEL_VIRTUAL_BASE equ 0xC0000000                  ; 3GB
KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22)  ; Page directory index of kernel's 4MB PTE.

align 0x1000
BootPageDirectory:
    ; This page directory entry identity-maps the first 4MB of the 32-bit physical address space.
    ; All bits are clear except the following:
    ; bit 7: PS The kernel page is 4MB.
    ; bit 1: RW The kernel page is read/write.
    ; bit 0: P  The kernel page is present.
    ; This entry must be here -- otherwise the kernel will crash immediately after paging is
    ; enabled because it can't fetch the next instruction! It's ok to unmap this page later.
    dd 0x00000083
    times (KERNEL_PAGE_NUMBER - 1) dd 0                 ; Pages before kernel space.
    ; This page directory entry defines a 4MB page containing the kernel.
    dd 0x00000083
    times (1024 - KERNEL_PAGE_NUMBER - 1) dd 0  ; Pages after the kernel image.


section .text
    ; reserve initial kernel stack space -- that's 16k.
    STACKSIZE equ 0x4000
    global loader
    global BootPageDirectory

        loader:

                    ;Enable Paging START

                    ; NOTE: Until paging is set up, the code must be position-independent and use physical
                    ; addresses, not virtual ones!
                    mov ecx, (BootPageDirectory - KERNEL_VIRTUAL_BASE)
                    mov cr3, ecx                                        ; Load Page Directory Base Register.

                    mov ecx, cr4
                    or ecx, 0x00000010                          ; Set PSE bit in CR4 to enable 4MB pages.
                    mov cr4, ecx

                    mov ecx, cr0
                    or ecx, 0x80000000                          ; Set PG bit in CR0 to enable paging.
                    mov cr0, ecx


                    lea ebx, [higherhalf]
                    jmp ebx ; Absolute Jump

        higherhalf:
            extern kernelMain
            extern callConstructors

                ; Unmap the identity-mapped first 4MB of physical address space. It should not be needed
                ; anymore.
                mov dword [BootPageDirectory], 0
                invlpg [0]

                mov esp, stack + STACKSIZE            ; set up the stack
                call callConstructors



              extern kernel_virtual_start
              extern kernel_virtual_end
              extern kernel_physical_start
              extern kernel_physical_end


                push kernel_virtual_end ; 2
                push 5
                push kernel_virtual_start ; 1
                push kernel_physical_start ; 3
                push kernel_physical_end ; 4
                push eax ; 5
                push ebx ; 6
                call kernelMain


                jmp _eof

        _eof:
             cli
             hlt 
             jmp _eof


section .bss
align 32
stack:
    resb STACKSIZE      ; reserve 16k stack on a uint64_t boundary

When i complete above i get these wierd characters when i print low and high memory (which give you ), as you can see here: https://www.youtube.com/watch?v=nDxSOkKd_NI . You can see full source code here: https://raw.githubusercontent.com/amanuel2/OS_Mirror . Help Would Be Appreciated.

amanuel2
  • 4,508
  • 4
  • 36
  • 67
  • I see the code above still has that stack issue a warned you about previously. – Michael Petch Aug 22 '16 at 04:04
  • In your video the physical end of memory is the multiboot magic number as well. That seems a bit odd too – Michael Petch Aug 22 '16 at 04:14
  • @MichaelPetch that sometimes happenes.. I dont know why either. – amanuel2 Aug 22 '16 at 04:27
  • Ok now that error is gone @MichaelPetch . but the Upper and Lower memory still exists . my printf function cant be wrong.. i have done tons of printing and didnt notice a single error.. also when i print the memory as a Hex %x , i get C010CA00 – amanuel2 Aug 22 '16 at 04:35
  • Well clearly the order you pass things to kernelMain is not the same as what boot.asm passes on the stack just prior to calling kernelMain. Also realize that EAX, ECX, and EDX will be clobbered when calling C/C++ function calls. It would appear EAX may be destroyed before you push it as a parameter when calling kernelMain. Parameters pushed on the stack are reverse of the order they appear in the function declaration. – Michael Petch Aug 22 '16 at 04:57
  • @MichaelPetch Just updated Code.. you can see i also added + Stacksize.. right now ever info is correct except the Upper Memory and Lower memory.. Yes also the physical end of kernel. about to go to sleep now – amanuel2 Aug 22 '16 at 05:03
  • Ok @MichaelPetch reversing order seemed to have fixed problem but now, i get 0x0 for all the kernel_physical_start , virtual_start, physical_end, virtual_end ... but correct memory... As you cann see on this viedo: https://www.youtube.com/watch?v=n40JYDYC6dA . When i print the palceholder i also get 0.. instead of 9 – amanuel2 Aug 22 '16 at 05:09
  • If you in fact have all the parameters in order (reverse) then you you are going to have to preserve _EAX_ before `call callConstructors` and restore it after. _EAX_ can be clobbered by `callConstructors`. You can easily do this by pushing _EAX_ before the call and popping it after. The **address** of the multiboot parameter is passed, so you need to change the function header `multiboot_info_t multiboot_structure` to be a **pointer** to the structure. `multiboot_info_t *multiboot_structure`. You'll then have to use `->` instead of `.` to access members. – Michael Petch Aug 22 '16 at 05:31
  • And MOST importantly. The address of the multiboot structure in _EBX_ has to be adjusted because it is not a higher half address. Before pushing _EBX_ onto the stack to call `kernelMain` you should do `add ebx, 0xC0000000` . Failure to do this will yield a memory address that will likely not work. – Michael Petch Aug 22 '16 at 05:33
  • Adding `0xC0000000` to the pointer can be done inside your _C_ code if you wish. You should be aware, ANY pointer given to you by GRUB has to be adjusted this way. – Michael Petch Aug 22 '16 at 05:44
  • @MichaelPetch when i convert multiboot_info_t into a pointer, i get triple fault , for some odd reason – amanuel2 Aug 22 '16 at 12:32
  • I have placed new copies of kernel.c++ and boot.asm on my website here - http://www.capp-sysware.com/misc/stackoverflow/39071105/ . This corrects all the issues I mentioned in the comments above. – Michael Petch Aug 22 '16 at 13:32
  • And one other thing I forgot to mention last night. You destroy _EBX_ as well before pushing it as a parameter. You do `lea ebx, [higherhalf]` `jmp ebx` which wiped out the value passed by GRUB. Change those two lines to use a different register like `lea ecx, [higherhalf]` `jmp ecx` – Michael Petch Aug 22 '16 at 13:49
  • @MichaelPetch ok so it all worked out with printing.. Thanks a lot! But now, i have another problem due to this! Whenever i try to type a character i get a page fault!!!!!! Why? Im still in debug state but no clue to this, here is viedo as evidence: https://www.youtube.com/watch?v=TxG52e3Btwo – amanuel2 Aug 22 '16 at 13:51
  • Well I didn't look beyond the bug you mentioned here. I believe your page fault with the keyboard input wasn't caused by my changes but one that existed previously. Did you try it with the original code to see if it was an issue? You aren't using a debugger yet to investigate these problems? – Michael Petch Aug 22 '16 at 13:52
  • @MichaelPetch actually nvm, its not your changes. And i dont mostly use debuggers , i manually debug them by commenting out code and see if that affects anything. If i do use a debugger, bochs or gdb will be the way to go.. but hard to use them correctly – amanuel2 Aug 22 '16 at 14:03
  • Using a proper debugger is easier than writing an OS – Michael Petch Aug 22 '16 at 14:15
  • Regarding the keyboard I'll give you something to look at. In your keyboard handler you have lines of code that have: `enter_press_np::val_e_inst.val_e`. I believe that `val_e` member is always null so when you attempt to access it as an array you are trying to access it at memory address 0x0 which will cause the fault. – Michael Petch Aug 22 '16 at 15:05
  • @MichaelPetch I delete everything in Keyboard handler, nothing changes... delete everything in irq_handler nothing changes... the problem is with common_irq_handler... trying to figure out what the problem is here: https://github.com/amanuel2/OS_Mirror/blob/master/irq.asm – amanuel2 Aug 22 '16 at 15:17
  • @MichaelPetch ok i will show you a viedo of it... right now i accidently shut down my VM , i will show you soon.. sec – amanuel2 Aug 22 '16 at 15:22
  • @MichaelPetch You can see in this viedo the only thing i have in keyboardhandler is printf("Keyboard"); .... When i run that.. i just press two characters, and i recieve Keyboard two times.. after that no matter how much i type, nothing appears. Here is the viedo: https://www.youtube.com/watch?v=sqOBILJ2ffU ... and yes i put return after printf("Keyboard"); same result.. I really need a tutorial on how to use a debugger.. the only debugger i was ever confartamble with was Visual Studio Debugger – amanuel2 Aug 22 '16 at 15:27
  • You are confused. It is not the same problem. You print `keyboard` on the screen with that new handler. There is no page fault anymore. The reason that you don't get subsequent interrupts is that you didn't retrieve a value from the keyboard chip. If you don't then future interrupts will not be generated. Before your `printf` add this line `p8b_kbd_drv.in(0x60);` and see what happens. – Michael Petch Aug 22 '16 at 15:30
  • @MichaelPetch ahh i see now.. well the nullptr statement you made above might be problem.. let me try to fix – amanuel2 Aug 22 '16 at 15:31
  • @MichaelPetch ok its all fixed.. one question, is the TOTAL/Usable RAM Memory Low + Memory High? – amanuel2 Aug 22 '16 at 20:03
  • Total memory and Usable RAM are not the same thing. Total memory will be close to Low + Memory High. If you want to know what usable memory is (areas you can potentially use by your OS/programs then you have to tell GRUB/multiboot loader to create a memory map (which you already do since you use the MEMINFO multiboot flag) and you will have to manually walk the multiboot memory table to find the usable areas. – Michael Petch Aug 22 '16 at 20:14
  • Memory Low and Memory high are in kilobytes. So to know how many bytes of RAM you multiple them by 1024. – Michael Petch Aug 22 '16 at 20:25
  • @MichaelPetch Ok My Biggest concern is Usable Memory.. because i am working on memory management ... and right now im trying to make page frame allocation , where i will need the usable memory – amanuel2 Aug 22 '16 at 20:27
  • @MichaelPetch which multiboot table are we talking about ? Since there many tables here: https://github.com/amanuel2/OS_Mirror/blob/master/multiboot.h – amanuel2 Aug 22 '16 at 20:29
  • You look in `multiboot_info` struct at the `multiboot_uint32_t mmap_length; multiboot_uint32_t mmap_addr;` entries. MMAP is the Memory Map. mmap_length is the total size of the memory containing the MAP and `mmap_addr` is a pointer to the address of that data (you will have to add 0xC0000000 to that address to make it high half before using it). You loop through all the entries (it is an array of `multiboot_mmap_entry` structs) finding the regions that are Available (Type 1). – Michael Petch Aug 22 '16 at 20:34
  • @MichaelPetch here when i assign variables i get a triple fault for some odd reason – amanuel2 Aug 22 '16 at 21:34
  • @MichaelPetch sorry forgot to give you the URL: https://github.com/amanuel2/OS_Mirror/blob/master/kernel.c%2B%2B#L74 – amanuel2 Aug 22 '16 at 21:44
  • You may have missed the part in my comment about converting the multiboot addresses into high half addresses. `multiboot_structure->mmap_addr` in your code will be an address < 1mb. Multiboot has no idea you remapped anything but when it created the memory map structure it was with addresses < 1mb. Unless you add 0xC0000000 to that address before using it you'll have issues. – Michael Petch Aug 22 '16 at 22:01
  • @MichaelPetch That happened to me with ViedoMemory To! Sorry forgot to notcie that, but even when i had + 0xC0000000 it has same error, not sure if this was the way i am suppose to do it? https://github.com/amanuel2/OS_Mirror/blob/master/kernel.c%2B%2B#L77 – amanuel2 Aug 22 '16 at 22:10
  • @MichaelPetch debuging it in qemu, gave this portion of log : https://gist.github.com/amanuel2/2a5647c4ebfe0471a1156c2d7def4e90 which states there is a page fault at address c0100f96 , which is the statement `c0100f96: 8b 40 14 mov 0x14(%eax),%eax` according to objdump : https://gist.github.com/amanuel2/cbd5a266c42284da38754d73d33fba34 . – amanuel2 Aug 22 '16 at 22:45
  • You didn't read what I said. You actually wrote code that added 0xC0000000 to the completely wrong values. You don't add them to the base address of the memory regions in the structure. You need to at it to the base of the memory map structure which is `multiboot_structure->mmap_addr` . You need to add 0xC0000000 to `multiboot_structure->mmap_addr` before you can use it. Remove the ones you did at it to. You added it to the length? Why? Do you understand highhalf addressing? – Michael Petch Aug 22 '16 at 22:54
  • @MichaelPetch yes i really udnerstand higher half adressing.. the reason im getting page fault is because i am accessing an invalid address. Sorry i didnt see that, let me do it.. i accidently closed my VM :( 2sec – amanuel2 Aug 22 '16 at 22:56
  • @MichaelPetch Dosent work still :( `multiboot_mmap_entry* mmap = (multiboot_mmap_entry*) multiboot_structure->mmap_addr + 0xC0000000;`.. code: https://github.com/amanuel2/OS_Mirror/blob/master/kernel.c%2B%2B#L69 – amanuel2 Aug 22 '16 at 23:03
  • Ok @MichaelPetch it works now.. but i did it a diffrent way than you did: https://github.com/amanuel2/OS_Mirror/blob/master/kernel.c%2B%2B#L86 . Now i get this.. Entry #0 , and then suddenly jumps to Entry #3 for some reason: http://imgur.com/VOaTe4V.png . Any reason for that? And how do i get usable memory from here on out? – amanuel2 Aug 22 '16 at 23:15
  • Yes because you told it to only list AVAILABLE entries. – Michael Petch Aug 22 '16 at 23:16
  • Oh Yeah @MichaelPetch .. ok i understand.. Now how do i get the Usable Memory , so i can use it for my page frame allocation wich will help me finish the memory management unit(malloc() and free()). – amanuel2 Aug 22 '16 at 23:18
  • You just did. The table you just iterated for AVAILABLE(USABLE memory) entries tells you exactly what ranges of memory are usable for memory management. Each Available(usable) area has a base address, and a length. It is up to you to take that data and use it in your memory management. How to do that can be done a whole pile of different ways, but you literally have a list of the memory you can use to map pages to. – Michael Petch Aug 22 '16 at 23:20
  • @MichaelPetch yea i understand but.. my question is.. Do i just take the length and add them up? And are they in KB Units? – amanuel2 Aug 22 '16 at 23:28
  • Those tables are all in bytes. If you want to know how much available memory can be used for Memory management then yes you add them up. On some systems though you may discover that there is more than 4GB of available memory so if you are adding things up be aware that on some systems you may need to deal with values exceeding 32-bits. You may also find on some systems that there are memory addresses that start above 4GB as well. `addr` and `len` in each entry are both 64-bit values but at the moment you are ignoring the top 32 bits. – Michael Petch Aug 22 '16 at 23:44
  • @MichaelPetch No.. uintptr_t makes it 32bit values for x86 systems and 64 bit value for x86_64 systems – amanuel2 Aug 22 '16 at 23:46
  • No, you are looking in the wrong place. The member fields of the MMAP entry are defined as `multiboot_uint64_t addr;` and `multiboot_uint64_t len;` . Where `multiboot_uint64_t` is defined at the top as `typedef unsigned long long multiboot_uint64_t;` . `Unsigned long long` on a 32-bit system is a 64-bit value. A 32-bit processor with properly written code deal with 64-bit values, 128-bit values even 65536 byte values (and higher, just using it as an example). An 8 bit processor can deal with large values than the size of a register with proper coding. – Michael Petch Aug 22 '16 at 23:48
  • You are likely confusing the fact that the memory address of the memory map structure itself fits into a 32-bit value. That part is true because GRUB creates those structures in memory below 1mb. But inside of each of those MMAP entries they are 64-bit values for the length and the address. – Michael Petch Aug 22 '16 at 23:52
  • @MichaelPetch Ok so your telling me to cast them to a uint32_t raher than uintptr_t like this : `uint32_t addr_low = ((uint32_t)mmap[i].addr);` ? – amanuel2 Aug 22 '16 at 23:54
  • No you should be storing the addresses in a size that can fit the entire value. You should be using a variable that is a `uint64_t` to store the `mmap[i].addr` and `mmap[i].len` . And if you want to print those values out as 64-bit values in your `printf` you will have to devise some mechanism to do that as well. I may be wrong but I think your `printf` only handles up to 32-bit values. – Michael Petch Aug 23 '16 at 00:00
  • @MichaelPetch As you can see my printf() %d for decimal core function lays out here: https://github.com/amanuel2/OS_Mirror/blob/master/stdio.c%2B%2B#L386 .. the major part is the `ch_per = va_arg(arg,int);` . I just get it as an int.. you want me have another like %64bit that has `ch_per = va_arg(arg,uint64_t);` ? – amanuel2 Aug 23 '16 at 00:05
  • Nvm changing it to `uint64_t` dosent do anything – amanuel2 Aug 23 '16 at 00:06
  • You have not been listening to anything I said. If you have values above 4GB or total memory is above 4GB it will be a problem. Your current emulator has less than 4GB so everything just happens to fit in 32-bit so it all looks fine. But if you have a 32-bit system with more than 4GB of RAM and the system has [Physical Address Extension support](https://en.wikipedia.org/wiki/Physical_Address_Extension) then you'll run into problems as the tables will have values for a base address and/or length that may not fit in the lower 32-bits of the fields you are using. – Michael Petch Aug 23 '16 at 00:10
  • @MichaelPetch Ok so how do i fix that problem? Or is it even fixable? And yes i do use PAE from enabling cr4.. as well has a Higher Half Kernel. – amanuel2 Aug 23 '16 at 00:14
  • Margaret Bloom write you an answer a few days back about bootloader (real mode at 0x7c00) and memory mapping. She actually took into account that address and length fields returned by the BIOS may be 64-bits wide. She displayed the entire 64-bit value to the display because she was aware that on some systems 32-bits may not be enough. She cheated because she was displaying in HEX and it is easy to print the top 32-bit followed by the lower 32-bits as separate values. You should go and look at her answer. – Michael Petch Aug 23 '16 at 00:14
  • You have at least two major issues in your `putchar` function. The one that causes the strange characters is caused by the fact that in `putchar` you define `ch_per` as `uint32_t ch_per` . That is unsigned. Later on in `putchar` for the `%d` case you do `if(ch_per<0)` . Since `ch_per` is unsigned `ch_per` is never less than zero. Your `itoa` routine is written in such a way that it only deal with unsigned values. If you pass `itoa` a negative numbers then `val % 10` will be negative and `(val % 10) + '0'` will be characters below ASCII 0. To fix change `uint32_t ch_per` to `int32_t ch_per` – Michael Petch Aug 23 '16 at 11:10
  • The second issue is in `putchar` as well and can lead to problems printing hex values that are less than 256. You define an unitialized array `char str_x[32];` near the top of the function. When doing `%x` processing you have this line `str_x[32] = {0};` I think you might have been attempting to zero the array out? This assignment places 0 in the byte one past the edge of the array and will clobber part of the next variable in memory on the stack. Maybe remove `str_x[32] = {0};` altogether and define and initialize the array to zero with `char str_x[32] = {0};` (if this was your intention) – Michael Petch Aug 23 '16 at 11:16
  • @MichaelPetch Ok ill fix those, but right now im trying to figure out what to do next in Memory Managmeent Unit, – amanuel2 Aug 23 '16 at 12:05
  • @MichaelPetch im at Managing Available Memory Section http://littleosbook.github.io/#managing-available-memory-1 , it says that "How do we know which page frames are in use? The page frame allocator needs to keep track of which are free and which aren’t. There are several ways to do this: bitmaps, linked lists, trees, the Buddy System etc" . Any Implementation examples of these so i atleast have the idea of what to do? Because right now im clueless on how to achive memory management (new() / malloc() and delete/ free() ) By the way got to bot in Real Hardware : http://i.imgur.com/UfS8AzI.png – amanuel2 Aug 23 '16 at 14:05
  • Ok @MichaelPetch . just have the copy of heap, just to see if it works .. dosent will be posting a question right now about the page fault – amanuel2 Aug 23 '16 at 19:20

1 Answers1

-1

Your code seems to have multiple errors -

1. Destruction of register values on calling static object constructors - When you execute the following code -

MOV ESP, stack + STACKSIZE
CALL callConstructors

then you need to save the register values that you are dependent on, and here EAX & EBX are crucial for holding the multiboot-related values. If any other registers are used before the call, they should be saved & you should read your ABI specification for caller/callee saved registers.

2. Parameters pushed in reverse order - This may seem awkward to you that your arguments to

push kernel_virtual_end ; 2
push 5
push kernel_virtual_start ; 1
push kernel_physical_start ; 3
push kernel_physical_end ; 4
push eax ; 5
push ebx ; 6
call kernelMain

call kernelMain are in reverse order, although you see them straight in code. You should have written your assembly-calling code as

push ebx ;6
push eax ; 5
push kernel_physical_end ; 4
push kernel_physical_start ; 3
push kernel_virtual_start ; 1
push 5
push kernel_virtual_end ; 2
call kernelMain

To understand why this is required, you should know that the IA32 stack grows downward. This means the value in ESP (address of processor stack) reduces by 4 (for 32-bit platform, otherwise 8 in 64-bit platform) on every

push <REG>

but in C, the first argument is the one at the lowest-address, or the one which is pushed last. Thus, you must push the arguments in a reverse-fashion in assembly code.

Shukant Pal
  • 706
  • 6
  • 19