/*
* Greets: All GNU Generation
*
* Author: Paulus Gandung Prakosa ([email protected])
*/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>

#define __vsys_fatal_error(msg) { \
       printk(KERN_ERR msg); \
}

#define __vsys_out(msg, fmt...) { \
       printk(KERN_INFO msg, ##fmt); \
}

#define __self_likely(arg)      __builtin_expect(!!(arg), 1)
#define __self_unlikely(arg)    __builtin_expect(!!(arg), 0)

struct control_register {
       unsigned long __cr0;
       unsigned long __cr2;
       unsigned long __cr3;
} __attribute__ ((packed));

static int __init __self_module_loader(void) {
       struct control_register *cr_t;

       cr_t = kmalloc(sizeof(*cr_t), GFP_KERNEL);
       if (__self_unlikely(cr_t == NULL)) {
               __vsys_fatal_error("Not enough memory to allocate.\n");
               return -1;
       }

#ifdef __x86_64__
       __vsys_out("Current system architecture is 64-bit.\n");

       asm volatile("movl      %%cr0, %%rax\n"
                    "movl      %%rax, %0\n"
                    "xorl      %%rax, %%rax\n"
                    "movl      %%cr2, %%rax\n"
                    "movl      %%rax, %1\n"
                    "xorl      %%rax, %%rax\n"
                    "movl      %%cr3, %%rax\n"
                    "movl      %%rax, %2\n"
                    "xorl      %%rax, %%rax\n"
                    : "=r" (cr_t->__cr0), "=r" (cr_t->__cr2), "=r" (cr_t->__cr3));
#elif defined(__i386__)
       __vsys_out("Current system architecture is 32-bit.\n");

       asm volatile("movl      %%cr0, %%eax\n"
                    "movl      %%eax, %0\n"
                    "xorl      %%eax, %%eax\n"
                    "movl      %%cr2, %%eax\n"
                    "movl      %%eax, %1\n"
                    "xorl      %%eax, %%eax\n"
                    "movl      %%cr3, %%eax\n"
                    "movl      %%eax, %2\n"
                    "xorl      %%eax, %%eax\n"
                    : "=r" (cr_t->__cr0), "=r" (cr_t->__cr2), "=r" (cr_t->__cr3));
#endif

       __vsys_out("cr0: 0x%08lx\n", cr_t->__cr0);
       __vsys_out("cr2: 0x%08lx\n", cr_t->__cr2);
       __vsys_out("cr3: 0x%08lx\n", cr_t->__cr3);

       kfree(cr_t);

       return 0;
}

static void __exit __self_module_unloader(void) {
       __vsys_out("Overall process done.\n");

       return;
}

MODULE_AUTHOR("Paulus Gandung Prakosa ([email protected])");
MODULE_DESCRIPTION("Control Register");
MODULE_LICENSE("GPL");

module_init(__self_module_loader);
module_exit(__self_module_unloader);