Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
And I'm getting this weird issue where after I call the pitd_wait() function, it seems like the emulator just skips right over the while loop and doesn't wait at all. However, if I print the value of the time_passed variable (by uncommenting the screen_printf() line) it does actually wait the set the amount of time. Any advice here would be much appreciated as I'm at a loss.
Edit: It seems like any function call fixes the issue, so now I'm wondering if this is the compiler doing something funky. Is it possible that for whatever reason the compiler is throwing out my loop?
Can you show how you declared `pitd_tick`? I will gather you didn't mark it as volatile so the compiler probably optimized the entire loop away. If you don't mark it volatile then the compiler will just assume its value never changed.
Can you compile the file with this code using the `-S` option to output the assembly code and post it here? Either that or objdump your kernel and show us the generated instructions for the function `void pitd_wait(uint32 ticks)`. Anything that can show us the generated code for that function will do.
When you called `pitd_init` what was the `clock_frequency` value you passed to the function? when you are calling `pitd_wait` what value for `ticks` did you pass into it?
No matter what value I pass, it doesn't wait. I've been testing with passing in the time in milliseconds. At the moment, I'm testing with the value of 5000 ticks, which should be around 5 seconds.
For completeness can you show the code for `p_write8`. Thanks. Do you have a Github project I can look at, or some way to build your code here so I can look at it?
You don't save and restore the registers. Since you are still doing all this in kernel mode this should get you started although you only really need to save/restore the volatile registers per the AMD64 System V ABI. This doesn't handle `swapgs`; 16 byte stack alignment; or anything but it should avoid your registers being corrupted while sitting in the `pitd_wait` function.
irq_asm:
push rax
push rbx
push rcx
push rdx
push rbp
push rdi
push rsi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
cld
call master_IRQ
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rbp
pop rdx
pop rcx
pop rbx
pop rax
iretq
The OSDev wiki I believe has more information on doing this properly and other things to consider.
You also take the slow approach to determining which IRQ fired. Your interrupt handler queries the PICs to figure that out. If you created an entry point for each IRQ in irq.asm then pass the interrupt number to `master_irq` as the first parameter it would be a better option.
You should also compile your kernel code with `-mno-red-zone` and consider disabling SIMD instructions with something like `-mno-mmx -mno-sse -mno-sse2`
Thank you, that fixed the problem. However, I don't plan on disabling the SSE registers, as I will be using floating point instructions in the future. Is there a way to save the SSE registers onto the stack and then restore them?
Yes. Subtract an appropriate amount from RSP to create a buffer where you can save the registers, then use FXSAVE/XSAVE/XSAVEC/XSAVEOPT/XSAVES to store them in that buffer. Afterwards, use FXRSTOR/XRSTOR/XRSTORS to restore them and add an appropriate amount to RSP to free the buffer.
It's also possible to save and restore the SSE registers one at a time, but I don't think there's any benefit to doing things that way.
Don't forget that your kernel's floating-point code will depend on things like the x87 FPU control and status words and MXCSR. It may be a good idea to "restore" a clean FPU state for your kernel code.
Improperly saving/restoring AVX registers can cause a performance penalty.