Plotting pixels to the screen using a physical Framebuffer (UEFI/GOP) - c

I’ve been recently getting into OS development (completely from scratch), and I’m stuck on an issue where plotting pixels to the screen does not seem to work at all.
For reference, I’m using EDK2 for the UEFI utilities and compiling my bootloader using its build system.
I obtain the framebuffer from the GOP handle after setting my wanted mode (which should be 1366x768, BGRA colour format), but writing any value to the framebuffer memory space seems to not translate anything to the screen. Here are the projects (bootloader and OS) for references:
* OS: https://github.com/kernel-dev/kernelOS
* Bootloader: https://github.com/kernel-dev/kernelOSBootloader
Furthermore, here are the relevant snippets of code that should work, but don’t:
* Function declarations: https://github.com/kernel-dev/kernelOS/blob/main/src/Kernel/Graphics/KernGraphics.c
* Calling the function for clearing the screen: https://github.com/kernel-dev/kernelOS/blob/main/src/Kernel/Kernel.c

Solved
The reason why it wasn't working is because I wasn't properly getting the passed down arguments in my kernel.
This is how it looked like:
// Entry point for kernel
VOID
KernMain (
IN EFI_RUNTIME_SERVICES *RT,
IN EFI_KERN_MEMORY_MAP *MemoryMap,
IN ACPI_DIFFERENTIATED_SYSTEM_DESCRIPTOR_TABLE *Dsdt,
IN KERN_FRAMEBUFFER *Framebuffer)
{
ScreenClearTerminal (Framebuffer);
//
// Should never reach here.
// Will be removed later.
//
while (TRUE) {};
}
However, the way I actually pass them down is like this:
//
// Prepare the arguments to be passed down.
//
LoaderBlock->MemoryMap = &MemoryMap;
LoaderBlock->Dsdt = Dsdt;
LoaderBlock->RT = SystemTable->RuntimeServices;
LoaderBlock->Framebuffer = FB;
//
// Exit boot services.
//
/* ... */
//
// Locate the EP function and call it with the arguments.
//
typedef void (__attribute__((ms_abi)) *EntryPointFunction) (LOADER_PARAMS *LP);
EntryPointFunction EntryPointPlaceholder = (EntryPointFunction) (BaseAddress + EntryPoint);
EntryPointPlaceholder (LoaderBlock);
It's contained inside of a struct. So the appropriate way to obtain them would be like this:
/**
A structure used to "contain" all
the parameters to be passed down
to the kernel's EP.
**/
typedef struct {
EFI_RUNTIME_SERVICES *RT; /// Pointer to the runtime services.
EFI_KERN_MEMORY_MAP *MemoryMap; /// Pointer to the EFI_KERN_MEMORY_MAP.
ACPI_DIFFERENTIATED_SYSTEM_DESCRIPTOR_TABLE **Dsdt; /// Pointer to the DSDT pointer.
KERN_FRAMEBUFFER *Framebuffer; /// Pointer to the KERN_FRAMEBUFFER.
} LOADER_PARAMS;
// Entry point for kernel
VOID
KernMain (
LOADER_PARAMS *LP)
{
ScreenClearTerminal (LP->Framebuffer);
//
// Should never reach here.
// Will be removed later.
//
while (TRUE) {};
}
or, alternatively keeping the old method, but alternating the way they're passed down:
//
// Locate the EP function and call it with the arguments.
//
typedef void (__attribute__((ms_abi)) *EntryPointFunction) (
EFI_RUNTIME_SERVICES *RT,
EFI_KERN_MEMORY_MAP *MemoryMap,
ACPI_DIFFERENTIATED_SYSTEM_DESCRIPTOR_TABLE **Dsdt,
KERN_FRAMEBUFFER *Framebuffer
);
EntryPointFunction EntryPointPlaceholder = (EntryPointFunction) (BaseAddress + EntryPoint);
EntryPointPlaceholder (
SystemTable->RuntimeServices,
&MemoryMap,
Dsdt,
FB);
Completely my bad lol.
Thank you to #user123 and #Dave S for helping me.

Related

How do you avoid using global variables in inherently stateful programs?

I am currently writing a small game in C and feel like I can't get away from global variables.
For example I am storing the player position as a global variable because it's needed in other files. I have set myself some rules to keep the code clean.
Only use a global variable in the file it's defined in, if possible
Never directly change the value of a global from another file (reading from another file using extern is okay)
So for example graphics settings would be stored as file scope variables in graphics.c. If code in other files wants to change the graphics settings they would have to do so through a function in graphics.c like graphics_setFOV(float fov).
Do you think those rules are sufficient for avoiding global variable hell in the long term?
How bad are file scope variables?
Is it okay to read variables from other files using extern?
Typically, this kind of problem is handled by passing around a shared context:
graphics_api.h
#ifndef GRAPHICS_API
#define GRAPHICS_API
typedef void *HANDLE;
HANDLE init_graphics(void);
void destroy_graphics(HANDLE handle);
void use_graphics(HANDLE handle);
#endif
graphics.c
#include <stdio.h>
#include <stdlib.h>
#include "graphics_api.h"
typedef struct {
int width;
int height;
} CONTEXT;
HANDLE init_graphics(void) {
CONTEXT *result = malloc(sizeof(CONTEXT));
if (result) {
result->width = 640;
result->height = 480;
}
return (HANDLE) result;
}
void destroy_graphics(HANDLE handle) {
CONTEXT *context = (CONTEXT *) handle;
if (context) {
free(context);
}
}
void use_graphics(HANDLE handle) {
CONTEXT *context = (CONTEXT *) handle;
if (context) {
printf("width = %5d\n", context->width);
printf("height = %5d\n", context->height);
}
}
main.c
#include <stdio.h>
#include "graphics_api.h"
int main(void) {
HANDLE handle = init_graphics();
if (handle) {
use_graphics(handle);
destroy_graphics(handle);
}
return 0;
}
Output
width = 640
height = 480
Hiding the details of the context by using a void pointer prevents the user from changing the data contained within the memory to which it points.
How do you avoid using global variables in inherently stateful programs?
By passing arguments...
// state.h
/// state object:
struct state {
int some_value;
};
/// Initializes state
/// #return zero on success
int state_init(struct state *s);
/// Destroys state
/// #return zero on success
int state_fini(struct state *s);
/// Does some operation with state
/// #return zero on success
int state_set_value(struct state *s, int new_value);
/// Retrieves some operation from state
/// #return zero on success
int state_get_value(struct state *s, int *value);
// state.c
#include "state.h"
int state_init(struct state *s) {
s->some_value = -1;
return 0;
}
int state_fini(struct state *s) {
// add free() etc. if needed here
// call fini of other objects here
return 0;
}
int state_set_value(struct state *s, int value) {
if (value < 0) {
return -1; // ERROR - invalid argument
// you may return EINVAL here
}
s->some_value = value;
return 0; // success
}
int state_get_value(struct state *s, int *value) {
if (s->some_value < 0) { // value not set yet
return -1;
}
*value = s->some_value;
return 0;
}
// main.c
#include "state.h"
#include <stdlib.h>
#include <stdio.h>
int main() {
struct state state; // local variable
int err = state_init(&state);
if (err) abort();
int value;
err = state_get_value(&state, &value);
if (err != 0) {
printf("Getting value errored: %d\n", err);
}
err = state_set_value(&state, 50);
if (err) abort();
err = state_get_value(&state, &value);
if (err) abort();
printf("Current value is: %d\n", value);
err = state_fini(&state);
if (err) abort();
}
The only single case where global variables (preferably only a single pointer to some stack variable anyway) have to be used are signal handlers. The standard way would be to only increment a single global variable of type sig_atomic_t inside a signal handler and do nothing else - then execute all signal handling related logic from the normal flow in the rest of the code by checking the value of that variable. (On POSIX system) all other asynchronous communication from the kernel, like timer_create, that take sigevent structure, they can pass arguments to notified function by using members in union sigval.
Do you think those rules are sufficient for avoiding global variable hell in the long term?
Subjectively: no. I believe that a potentially uneducated programmer has too much freedom in creating global variables given the first rule. In complex programs I would use a hard rule: Do not use global variables. If finally after researching all other ways and all other possibilities have been exhausted and you have to use a global variables, make sure global variables leave the smallest possible memory footprint.
In simple short programs I wouldn't care much.
How bad are file scope variables?
This is opinion based - there are good cases where projects use many global variables. I believe that topic is exhausted in are global variables bad and numerous other internet resources.
Is it okay to read variables from other files using extern?
Yes, it's ok.
There are no "hard rules" and each project has it's own rules. I also recommend to read c2 wiki global variables are bad.
The first thing you have to ask yourself is: Just why did the programming world come to loath global variables? Obviously, as you noted, the way to model a global state is essentially a global (set of) variable(s). So what's the problem with that?
The Problem
All parts of the program have access to that state. The whole program becomes tightly coupled. Global variables violate the prime directive in programming, divide and conquer. Once all functions operate on the same data you can as well do away with the functions: They are no longer logical separations of concern but degrade to a notational convenience to avoid large files.
Write access is worse than read access: You'll have a hard time finding out just why on earth the state is unexpected at a certain point; the change can have happened anywhere. It is tempting to take shortcuts: "Ah, we can make the state change right here instead of passing a computation result back up three layers to the caller; that makes the code much smaller."
Even read access can be used to cheat and e.g. change behavior of some deep-down code depending on some global information: "Ah, we can skip rendering, there is no display yet!" A decision which should not be made in the rendering code but at top level. What if top level renders to a file!?
This creates both a debugging and a development/maintenance nightmare. If every piece of the code potentially relies on the presence and semantics of certain variables — and can change them! — it becomes exponentially harder to debug or change the program. The code agglomerating around the global data is like a cast, or perhaps a Boa Constrictor, which starts to immobilize and strangle your program.
Such programming can be avoided with (self-)discipline, but imagine a large project with many teams! It's much better to "physically" prevent access. Not coincidentally all programming languages after C, even if they are otherwise fundamentally different, come with improved modularization.
So what can we do?
The solution is indeed to pass parameters to functions, as KamilCuk said; but each function should only get the information they legitimately need. Of course it is best if the access is read-only and the result is a return value: Pure functions cannot change state at all and thus perfectly separate concerns.
But simply passing a pointer to the global state around does not cut the mustard: That's only a thinly veiled global variable.
Instead, the state should be separated into sub-states. Only top-level functions (which typically do not do much themselves but mostly delegate) have access to the overall state and hand sub-states to the functions they call. Third-tier functions get sub-sub states, etc. The corresponding implementation in C is a nested struct; pointers to the members — const whenever possible — are passed to functions which therefore cannot see, let alone alter, the rest of the global state. Separation of concerns is thus guaranteed.

Raising RAM in load BMP function SDL

I'm using SDL to code a simple game, and i have a big problem - i'm trying to do some animations with function,
in the fuction i call static int which keeps raising every game tick, and dependant on value of static int i change my variable image (with image=SDL_LoadBMP(myfile)), it's working great, but after 10 minutes of running a program, which had been working with 50MB of memory before without this really simple animation, ram usage of my program is starting to get bigger and bigger, and as i said, after 10 minutes it's 3GB and keeps raising every animation occur(so, like every 3 seconds).
Weird thing is also that i have other image which animation is a little bit simplier - i change my image upon clicking any arrow (still in main), and then call function, so after a second it gives back the initial image to a variable(it's giving image back in function), and it's working great - with that i mean - even if i keep clicking arrows, memory usage is constant.
my function looks like that:
void func(obj* image)
{
static int time1;
time1++;
if(time1>1000)
{
time1=0;
SDL_FreeSurface(image->image); //this doesn't change anything
image->image=SDL_LoadBMP("path");
}
else if(time1>800)
image->image=SDL_LoadBMP("path2");
else if(time1>600)
image->image=SDL_LoadBMP("path3");
else if(time1>400)
image->image=SDL_LoadBMP("path4");
}
typedef struct {
SDL_Surface* image;
}obj;
int main()
{
obj struct;
func(&struct);
}
ofc it's fulfilled with all this SDL library calls to make a window etc
https://i.ibb.co/YBcvjnF/Bez-tytu-u.png
If I understand correctly you're making SDL_Surface* over and over again, you never call SDL_FreeSurface()(info).
You need to load a some point all the BMP needed to play the animation into SDL_Surface* then reuse these BMP(s).
In your main (or into an init function) you need to store into an array or pointers the BMP images.
// Somewhere on one of your struct
SDL_Surface *animationImages[4];
// Then in an init function you do
animationImages[0] = SDL_LoadBMP("path");
animationImages[1] = SDL_LoadBMP("path2");
animationImages[2] = SDL_LoadBMP("path3");
animationImages[3] = SDL_LoadBMP("path4");
// And finally
void func(obj* image) {
static int time1;
time1++;
if (time1>1000) {
time1 = 0;
image->image = animationImages[0];
} else if (time1>800) {
image->image = animationImages[1];
} else if (time1>600) {
image->image = animationImages[2];
} else if (time1>400) {
image->image = animationImages[3];
}
}
And before the end of your game or when you don't need these animationImages anymore call SDL_FreeSurface() for each SDL_Surface* you have created.
// In a specific function used to clean up allocated stuff you do
SDL_FreeSurface(animationImages[0]);
SDL_FreeSurface(animationImages[1]);
SDL_FreeSurface(animationImages[2]);
SDL_FreeSurface(animationImages[3]);

Store extra data in a c function pointer

Suppose there is a library function (can not modify) that accept a callback (function pointer) as its argument which will be called at some point in the future. My question: is there a way to store extra data along with the function pointer, so that when the callback is called, the extra data can be retrieved. The program is in c.
For example:
// callback's type, no argument
typedef void (*callback_t)();
// the library function
void regist_callback(callback_t cb);
// store data with the function pointer
callback_t store_data(callback_t cb, int data);
// retrieve data within the callback
int retrieve_data();
void my_callback() {
int a;
a = retrieve_data();
// do something with a ...
}
int my_func(...) {
// some variables that i want to pass to my_callback
int a;
// ... regist_callback may be called multiple times
regist_callback(store_data(my_callback, a));
// ...
}
The problem is because callback_t accept no argument. My idea is to generate a small piece of asm code each time to fill into regist_callback, when it is called, it can find the real callback and its data and store it on the stack (or some unused register), then jump to the real callback, and inside the callback, the data can be found.
pseudocode:
typedef struct {
// some asm code knows the following is the real callback
char trampoline_code[X];
callback_t real_callback;
int data;
} func_ptr_t;
callback_t store_data(callback_t cb, int data) {
// ... malloc a func_ptr_t
func_ptr_t * fpt = malloc(...);
// fill the trampoline_code, different machine and
// different calling conversion are different
// ...
fpt->real_callback = cb;
fpt->data = data;
return (callback_t)fpt;
}
int retrieve_data() {
// ... some asm code to retrive data on stack (or some register)
// and return
}
Is it reasonable? Is there any previous work done for such problem?
Unfortunately you're likely to be prohibited from executing your trampoline in more and more systems as time goes on, as executing data is a pretty common way of exploiting security vulnerabilities.
I'd start by reporting the bug to the author of the library. Everybody should know better than to offer a callback interface with no private data parameter.
Having such a limitation would make me think twice about how whether or not the library is reentrant. I would suggest ensuring you can only have one call outstanding at a time, and store the callback parameter in a global variable.
If you believe that the library is fit for use, then you could extend this by writing n different callback trampolines, each referring to their own global data, and wrap that up in some management API.

Need to write algorithm in state-machine style, but it becomes very hard to read

I work on embedded device's firmware (write in C), I need to take a screenshot from the display and save it as a bmp file. Currently I work on the module that generates bmp file data. The easiest way to do that is to write some function that takes the following arguments:
(for simplicity, only images with indexed colors are supported in my example)
color_depth
image size (width, height)
pointer to function to get palette color for color_index (i)
pointer to function to get color_index of the pixel with given coords (x, y)
pointer to function to write image data
And then user of this function should call it like that:
/*
* Assume we have the following functions:
* int_least32_t palette_color_get (int color_index);
* int pix_color_idx_get (int x, int y);
* void data_write (const char *p_data, size_t len);
*/
bmp_file_generate(
1, //-- color_depth
x, y, //-- size
palette_color_get,
pic_color_idx_get,
data_write
);
And that's it: this functions does all the job, and returns only when job is done (i.e. bmp file generated and "written" by given user callback function data_write().
BUT, I need to make bmp_writer module to be usable in cooperative RTOS, and data_write() might be a function that actually transmits data via some protocol (say, UART) to another device), so, this function needs to be called only from Task context. This approach doesn't work then, I need to make it in OO-style, and its usage should look like this:
/*
* create instance of bmp_writer with needed params
* (we don't need "data_write" pointer anymore)
*/
T_BmpWriter *p_bmp_writer = new_bmp_writer(
1, //-- color_depth
x, y, //-- size
palette_color_get,
pic_color_idx_get
);
/*
* Now, byte-by-byte get all the data!
*/
while (bmp_writer__data_available(p_bmp_writer) > 0){
char cur_char = bmp_writer__get_next_char(p_bmp_writer);
//-- do something useful with current byte (i.e. cur_char).
// maybe transmit to another device, or save to flash, or anything.
}
/*
* Done! Free memory now.
*/
delete_bmp_writer(p_bmp_writer);
As you see, user can call bmp_writer__get_next_char(p_bmp_writer) when he need that, and handle received data as he wants.
Actually I already implemented this, but, with that approach, all the algorithm becomes turned inside out, and this code is extremely non-readable.
I'll show you a part of old code that generates palette data (from the function that does all the job, and returns only when job is done), and appropriate part of new code (in state-machine style).
Old code:
void bmp_file_generate(/*....args....*/)
{
//-- ... write headers
//-- write palette (if needed)
if (palette_colors_cnt > 0){
size_t i;
int_least32_t cur_color;
for (i = 0; i < palette_colors_cnt; i++){
cur_color = callback_palette_color_get(i);
callback_data_write((const char *)&cur_color, sizeof(cur_color));
}
}
//-- ...... write image data ..........
}
As you see, very short and easy-readable code.
Now, new code.
It looks like state-machine, because it's actually splitted by stages (HEADER_WRITE, PALETTE_WRITE, IMG_DATA_WRITE), each stage has its own context. In the old code, context was saved in local variables, but now we need to make the structure and allocate it from heap.
So:
/*
* Palette stage context
*/
typedef struct {
size_t i;
size_t cur_color_idx;
int_least32_t cur_color;
} T_StageContext_Palette;
/*
* Function that switches stage.
* T_BmpWriter is an object context, and pointer *me is analogue of "this" in OO-languages.
* bool_start is 1 if stage is just started, and 0 if it is finished.
*/
static void _stage_start_end(T_BmpWriter *me, U08 bool_start)
{
switch (me->stage){
//-- ...........other stages.........
case BMP_WR_STAGE__PALETTE:
if (bool_start){
//-- palette stage is just started. Allocate stage context and initialize it.
me->p_stage_context = malloc(sizeof(T_StageContext_Palette));
memset(me->p_stage_context, 0x00, sizeof(T_StageContext_Palette));
//-- we need to get first color, so, set index of byte in cur_color to maximum
((T_StageContext_Palette *)me->p_stage_context)->i = sizeof(int_least32_t);
} else {
free(me->p_stage_context);
me->p_stage_context = NULL;
}
break;
//-- ...........other stages.........
}
}
/*
* Function that turns to the next stage
*/
static void _next_stage(T_BmpWriter *me)
{
_stage_start_end(me, 0);
me->stage++;
_stage_start_end(me, 1);
}
/*
* Function that actually does the job and returns next byte
*/
U08 bmp_writer__get_next_char(T_BmpWriter *me)
{
U08 ret = 0; //-- resulting byte to return
U08 bool_ready = 0; //-- flag if byte is ready
while (!bool_ready){
switch (me->stage){
//-- ...........other stages.........
case BMP_WR_STAGE__PALETTE:
{
T_StageContext_Palette *p_stage_context =
(T_StageContext_Palette *)me->p_stage_context;
if (p_stage_context->i < sizeof(int_least32_t)){
//-- return byte of cur_color
ret = *( (U08 *)&p_stage_context->cur_color + p_stage_context->i );
p_stage_context->i++;
bool_ready = 1;
} else {
//-- need to get next color (or even go to next stage)
if (p_stage_context->cur_color_idx < me->bmp_details.palette_colors_cnt){
//-- next color
p_stage_context->cur_color = me->callback.p_palette_color_get(
me->callback.user_data,
p_stage_context->cur_color_idx
);
p_stage_context->cur_color_idx++;
p_stage_context->i = 0;
} else {
//-- next stage!
_next_stage(me);
}
}
}
break;
//-- ...........other stages.........
}
}
return ret;
}
So huge code, and it's so hard to understand it!
But I really have no idea how to make it in some different way, to be able to get information byte-by-byte.
Does anyone know how to achieve this, and keep code readability?
Any help is appreciated.
You can try protothread, which is useful to transform a state-machine based program into thread-style program. I'm not 100% sure that it can solve your problem elegantly, you can give it a try. The paper is a good starting point: Protothreads: simplifying event-driven programming of memory-constrained embedded systems
Here is its source code: http://code.google.com/p/protothread/
By the way, protothread is also used in the Contiki embedded OS, for implementing process in Contiki.

Can I replace a Linux kernel function with a module?

Im getting into kernel work for a bit of my summer research. We are looking to make modifications to the TCP, in specific RTT calculations. What I would like to do is replace the resolution of one of the functions in tcp_input.c to a function provided by a dynamically loaded kernel module. I think this would improve the pace at which we can develop and distribute the modification.
The function I'm interested in was declared as static, however I've recompiled the kernel with the function non-static and exported by EXPORT_SYMBOL. This means the function is now accessible to other modules/parts of the kernel. I have verified this by "cat /proc/kallsyms".
Now I'd like to be able to load a module that can rewrite the symbol address from the initial to my dynamically loaded function. Similarly, when the module is to be unloaded, it would restore the original address. Is this a feasible approach? Do you all have suggestions how this might be better implemented?
Thanks!
Same as Overriding functionality with modules in Linux kernel
Edit:
This was my eventual approach.
Given the following function (which I wanted to override, and is not exported):
static void internal_function(void)
{
// do something interesting
return;
}
modify like so:
static void internal_function_original(void)
{
// do something interesting
return;
}
static void (*internal_function)(void) = &internal_function_original;
EXPORT_SYMBOL(internal_function);
This redefines the expected function identifier instead as a function pointer (which can be called in a similar manner) pointing to the original implementation. EXPORT_SYMBOL() makes the address globally accessible, so we can modify it from a module (or other kernel location).
Now you can write a kernel module with the following form:
static void (*original_function_reference)(void);
extern void (*internal_function)(void);
static void new_function_implementation(void)
{
// do something new and interesting
// return
}
int init_module(void)
{
original_function_reference = internal_function;
internal_function = &new_function_implementation;
return 0;
}
void cleanup_module(void)
{
internal_function = original_function_reference;
}
This module replaces the original implementation with a dynamically loaded version. Upon unloading, the original reference (and implementation) is restored. In my specific case, I provided a new estimator for the RTT in TCP. By using a module, I am able to make small tweaks and restart testing, all without having to recompile and reboot the kernel.
I'm not sure that'll work - I believe the symbol resolution for the internal calls to the function you want to replace will have already been done by the time your module loads.
Instead, you could change the code by renaming the existing function, then creating a global function pointer with the original name of the function. Initialise the function pointer to the address of the internal function, so the existing code will work unmodified. Export the symbol of the global function pointer, then your module can just change its value by assignment at module load and unload time.
I once made a proof of concept of a hijack module that inserted it's own function in place of kernel function.
I just so happens that the new kernel tacing architecture uses a very similar system.
I injected my own function in the kernel by overwriting the first couple of bytes of code with a jump pointing to my custom function. As soon as the real function gets called, it jumps instead to my function that after it had done it's work called the original function.
#include <linux/module.h>
#include <linux/kernel.h>
#define CODESIZE 12
static unsigned char original_code[CODESIZE];
static unsigned char jump_code[CODESIZE] =
"\x48\xb8\x00\x00\x00\x00\x00\x00\x00\x00" /* movq $0, %rax */
"\xff\xe0" /* jump *%rax */
;
/* FILL THIS IN YOURSELF */
int (*real_printk)( char * fmt, ... ) = (int (*)(char *,...) )0xffffffff805e5f6e;
int hijack_start(void);
void hijack_stop(void);
void intercept_init(void);
void intercept_start(void);
void intercept_stop(void);
int fake_printk(char *, ... );
int hijack_start()
{
real_printk(KERN_INFO "I can haz hijack?\n" );
intercept_init();
intercept_start();
return 0;
}
void hijack_stop()
{
intercept_stop();
return;
}
void intercept_init()
{
*(long *)&jump_code[2] = (long)fake_printk;
memcpy( original_code, real_printk, CODESIZE );
return;
}
void intercept_start()
{
memcpy( real_printk, jump_code, CODESIZE );
}
void intercept_stop()
{
memcpy( real_printk, original_code, CODESIZE );
}
int fake_printk( char *fmt, ... )
{
int ret;
intercept_stop();
ret = real_printk(KERN_INFO "Someone called printk\n");
intercept_start();
return ret;
}
module_init( hijack_start );
module_exit( hijack_stop );
I'm warning you, when you're going to experiment with these kind of things, watch out for kernel panics and other disastrous events. I would advise you to do this in a virtualised environment. This is a proof-of-concept code I wrote a while ago, I'm not sure it still works.
It's a really easy principle, but very effective. Of course, a real solution would use locks to make sure nobody would call the function while you're overwriting it.
Have fun!
You can try using ksplice - you don't even need to make it non static.
I think what you want is Kprobe.
Another way that caf has mentioned is to add a hook to the original routine, and register/unregister hook in the module.

Resources