2
\$\begingroup\$

Here's my inline-assembly functions, which is used my x86 32bit kernel.

static inline uint8_t ckPortInByte(uint16_t port)
{
    uint8_t ret;
    __asm__ __volatile__ ( "in %1, %0" : "=a"(ret) : "d"(port) );
    return ret;
}

static inline void ckPortOutByte(uint16_t port, uint8_t data)
{
    __asm__ __volatile__ ( "out %0, %1" : : "a"(data), "d"(port) );
}

static inline uint32_t ckAsmGetEFlag()
{
    uint32_t ret;
    __asm__ __volatile__ ( "pushfl \n pop %0" : "=g"(ret) );
    return ret;
}

static inline void ckAsmSetEFlag(uint32_t eflag)
{
    __asm__ __volatile__ ( "push %0 \n popfl" : : "g"(eflag) );
}

static inline uint32_t ckGetCr0()
{
    uint32_t ret;
    __asm__ ( "mov %%cr0, %0" : "=r"(ret) );
    return ret;
}

static inline void ckSetCr0(uint32_t value)
{
    __asm__ ( "mov %0, %%cr0" : : "r"(value) );
}

static inline uint32_t ckGetCr3()
{
    uint32_t ret;
    __asm__ ( "mov %%cr3, %0 " : "=r"(ret) );
    return ret;
}

static inline void ckSetCr3(uint32_t value)
{
    __asm__ ( "mov %0, %%cr3" : : "r"(value) );
}

static inline void ckAsmCpuid(uint32_t code, CpuidStruct *cs)
{
    __asm__
    (
        "cpuid"
        : "=a"(cs->eax), "=b"(cs->ebx), "=c"(cs->ecx), "=d"(cs->edx)
        : "a"(code)
    );
}

static inline void ckAsmCli()
{
    __asm__ __volatile__ ( "cli" );
}

static inline void ckAsmSti()
{
    __asm__ __volatile__ ( "sti" );
}

static inline void ckAsmStiHlt()
{
    __asm__ __volatile__ ( "sti \n hlt" );
}

static inline void ckAsmHlt()
{
    __asm__ __volatile__ ( "hlt" );
}

It seems that everything is ok.

However, recently I had a bug, which is related to these functions, especially __volatile__ correctness. (Can you see __volatile__ in ckPortInByte and ckPortOutByte? They didn't exist before I fixed it...)

So, I'm really afraid now - Is there anything wrong? (i.e. unnecessary or missing __volatile__)

\$\endgroup\$
1
\$\begingroup\$

Your use of volatile appears to be correct, but I think you should do a couple of things for safety:

  • Add a clobber constraint for the flags (AKA "condition codes") to ckAsmSetEFlag. I believe this is "cc" for x86 machines.
  • Add clobber constraints for CR0 and CR3 to ckSetCr0 and ckSetCr3, respectively. [edit] This appears to be impossible with GCC. Not sure if this is a problem or not.[/edit]

While GCC's inline assembly syntax is very powerful, it can be horribly unintuitive. Since you're writing a kernel and messing with control registers, you really should be checking the assembly listings for every module you compile, to verify that the compiler is honouring your intentions.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ As far as your specific bugs go, it's going to be very hard to tell what's going on without seeing the calling functions and other surrounding code. If you have repository perhaps you could link to it on code review? \$\endgroup\$ – linguamachina Jun 6 '14 at 8:54
  • \$\begingroup\$ I don't have no repository, yet.. Anyway, I haven't ever known that there are "cc" clobber and control-register clobber (I think gcc doesn't support it..). Thank you! \$\endgroup\$ – ikh Jun 6 '14 at 11:57
  • \$\begingroup\$ By the way, if I use "cc" clobber, __volatile__ of ckAsmGetEFlag and ckAsmSetEFlag become unnecessary? \$\endgroup\$ – ikh Jun 6 '14 at 11:58
  • 1
    \$\begingroup\$ "g" constraint? See here: Any register, memory or immediate integer operand is allowed, except for registers that are not general registers. \$\endgroup\$ – ikh Jun 6 '14 at 12:00
  • \$\begingroup\$ Adding clobbers does not eliminate the need for volatile. Nosireekenneth. Re: "g": Thanks for clearing that one up. GCC definitely supports the cc constraint for the flags, but you're right, it chokes on control registers. To be on the safe side, I would consider writing such portions of your kernel in assembly separately, and calling them from your C/C++ code. \$\endgroup\$ – linguamachina Jun 6 '14 at 12:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.