cx86floating-pointprotected-mode

C kernel is going crazy with floating point numbers


So I'm writing a C kernel (which runs in protected mode) and I'm dabbling with floating point numbers. First, I wrote this C program to make sure that nothing goes wrong (runs on my physical machine, not as part of the kernel) that used a for loop to increment a float value by 1.0f every time and display the result which worked as expected:

#include <stdio.h>

int main() {
    float numba;
    for(int i = 0; i < 100; i++) {
        numba = numba + 1.0f;
        printf("%d\n", (unsigned int)numba);
    }
}

1
2
3
4
...
99
100

Considering that I cannot use printf in my kernel, I had to implement that in some other way :P. Using the pixel drawing routine:

void putPixel(MODEINFOBLOCK mib, unsigned int x, unsigned int y, unsigned int color);

... I can make a perfect diagonal line. How? By incrementing the for loop's counter and numba, I am able to use them as the X and Y coordinates for the routine:

float numba;
for(int i = 0; i < 100; i++) {
    numba = numba + 1.0f;
    putPixel(mib, i, (unsigned int)numba, 0xFFFFFF);
}

However, I get this when I run the kernel:

reality

Apparently it is giving me numba = 0 every time and therefore it doesn't work as expected:

expectation (plzzz don't ask me how I took this screenshot :PP)

By looking at the kernel's disassembly, I didn't notice anything very suspicious:

 1ef:   83 c4 10                add    esp,0x10
 1f2:   bb 00 00 00 00          mov    ebx,0x0
 1f7:   d9 44 24 08             fld    DWORD PTR [esp+0x8]
 1fb:   d8 05 f4 10 10 00       fadd   DWORD PTR ds:0x1010f4
 201:   d9 54 24 08             fst    DWORD PTR [esp+0x8]
 205:   83 ec 0c                sub    esp,0xc
 208:   68 ff ff ff 00          push   0xffffff
 20d:   d9 7c 24 1e             fnstcw WORD PTR [esp+0x1e]
 211:   0f b7 44 24 1e          movzx  eax,WORD PTR [esp+0x1e]
 216:   80 cc 0c                or     ah,0xc
 219:   66 89 44 24 1c          mov    WORD PTR [esp+0x1c],ax
 21e:   d9 6c 24 1c             fldcw  WORD PTR [esp+0x1c]
 222:   df 7c 24 10             fistp  QWORD PTR [esp+0x10]
 226:   d9 6c 24 1e             fldcw  WORD PTR [esp+0x1e]
 22a:   ff 74 24 10             push   DWORD PTR [esp+0x10]
 22e:   53                      push   ebx
 22f:   81 ec 18 01 00 00       sub    esp,0x118
 235:   be 40 1c 10 00          mov    esi,0x101c40
 23a:   b9 46 00 00 00          mov    ecx,0x46
 23f:   89 e7                   mov    edi,esp
 241:   f3 a5                   rep movs DWORD PTR es:[edi],DWORD PTR ds:[esi]
 243:   e8 2c 01 00 00          call   0x374
 248:   83 c3 01                add    ebx,0x1
 24b:   81 c4 30 01 00 00       add    esp,0x130
 251:   83 fb 64                cmp    ebx,0x64
 254:   75 a1                   jne    0x1f7
 256:   e8 0c 00 00 00          call   0x267
 25b:   e8 0d 00 00 00          call   0x26d
 260:   83 c4 10                add    esp,0x10
 263:   5b                      pop    ebx
 264:   5e                      pop    esi
 265:   5f                      pop    edi

As you can see, the kernel is using FPU instructions. However, the program doesn't for some reason.

And the question is... Why does this happen? Is there something with FPUs in protected mode?

NOTE: This is literally my first time dealing with FP numbers, so I KNOW the answer for this question will seem obvious for y'all (I hope.)


Solution

  • numba not initialized.

    // float numba;
    float numba = 0.0f;
    
    for(int i = 0; i < 100; i++) {
        numba = numba + 1.0f;
        putPixel(mib, i, (unsigned int)numba, 0xFFFFFF);
    }