How Linux Kernel Prints Text on Screen

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
let's take a look at what happens under the hood when you call Print F what happens inside of the Linux kernel and finally how does it get printed on the screen for this I'm going to use GDB I'm going to debug the kernel I have here the guide from the Linux kernel docs we're going to follow it and I'm going to start by configuring the kernel for GDB for this I'm going to go over here where I Clon the kernel I'm going to put information about everything in the description I'm going to start by running make and then def config and this will initialize a default configuration afterwards we're going to run make and then many config I'm going to scroll here to the bottom and press enter on kernel hacking afterwards I'm going to press enter on compiler options over here debug information I'm going to set to default dwarf version press enter on this I'm going to also press space on this line provide GDB scripts this will be useful let's finally exit and save the changes now I'm going to start the build by running make I'm going to also use minus j8 to make it faster notice that in my case though it's going to run really fast cuz I already built the kernel now we can see that the bz image is ready this is the kernel that we're going to use now let's go back to the guide for a sec another important thing here is that we're going to run make scripts GTP this will pair the GTB scripts we're going to use now let's go ahead and prepare the user space so I'm going to make a simple program that will just print hello world so I have here an empty directory called the drro let's create a new file it's called in it. C we're going to make a simple call for printf so I'm going to use stdio start my main function over here now let's go ahead and save this and I'm going to build this using GCC I'm going to pass in minus static this is important because this will be the only executable in our user space so it has to be static and the output is just going to be named in it now we have here an init executable we can go ahead and run this works fine also notice that if I use srace on the init executable we can see the system calls that are initiated by this executable specifically this is the main one we're interested in it's called right even though we call prf under the hood prf eventually uses right because right is what is actually implemented in the kernel you can see that one of the parameters here is the hello world we use with printf and the first parameter is the file descriptor in the case of SCD out it's file descriptor number one by the way you can find more information about system call by just using the man page Category 2 pass in the system call name for example right and you can see are the parameters and more information about this anyway we're going to take a look at where this is implemented inside of the kernel before that I want to prepare the in ramfs cuz now we need to create the init ramfs archive so the kernel can work with this for this we can use the CPI o utility I'm going to first pass in the file that I want to use in this case it's going to be init that's going to be only one file so I'm going to Echo in it I'm going to pipe this into into cpio minus H is going to be new C that's going to be the format new C is the format that is supported by the kernel minus o is going to tell cpio to create a new archive finally I'm going to pipe this into in it. cpio now we got the archive right over here this is our init ramfs and it contains only a single file and that is the init executable we just built now let's go back to the directory we built Linux let's take a quick look at the source code I'm going to show you something so we're going to go to the fs Direct Dory and read write. C over here let's navigate to CIS and then write we can see how we have here the casis WR function we're going to see where this is used and we can see here the CIS call Define 3 macro this defines a new system call system call is called right and here are the parameters by the way we have here the three because the right system call has three parameters and we can see the way that right is implemented is that it just calls casis right so we know from here that in order to actually understand what is going on we're going to put a breakpoint on this function now let's start GDB with the VM Linux as they tell us over here in the debugging guide also notice that you may need to configure the safe path like it says over here I have it configured in the GDB init file we're telling GDB that it's fine to load stuff from this directory this is directory I have Linux clone in so now I'm going to start GDB like this and finally after it read the symbols from VM Linux the GDB prompt just started so now GDB is configured for kernel debugging now it's time to start the kernel for this I'm going to use qmu system x864 I'm going to pass minus kernel pass in the paths the Bez image we just built that is an arch x86 64 second parameter is going to be init Rd here I'm going to pass the init ramfs we built we put this in drro and then initcpio afterwards I'm going to pass minus s and minus capital S these flags will tell qmu to wait for the debugger to connect and also to start suspended finally I'm going to use minus append this will enable me to pass in more command line parameters for the kernel and I'm going to pass in no K aslr this will disable a security feature that is called K aslr aslr stands for address based layout randomization and this is a security feature which changes the address the kernel is loaded into each time the kernel boots but this will confuse the debugger so I'm going to just disable it now we can go ahead and run this you can see now that qmu is paused it's waiting for the debugger to connect so we can go ahead and close this and now I'm going to connect with GDB so I'm going to run Target remote connect to Port 1 2 3 4 and you can see now we're successfully connected so I'm going to start by placing a breake point with the brake command going to be on casis right as we saw before this is where the right system call is implemented now I'm going to run continue it's going to continue the boot of the kernel now you can see the kernel is booting right over here and now you can see the breako was hit and indeed the last line that the kernel printed over here was run in it as in it process so now the kernel is in the middle of running our init process that we just wrote and we can see here in the parameters that indeed this is the hello world that we wrote so what I'm going to do is I'm going to use the list command this will show me the lines of code over here and I'm going to press enter to see more of the code what we can see here in the code is that it starts by checking which file is related to the file descriptor that was passed and it gets back this structure that is called FD and then it's doing a bunch of initialization and eventually calling VFS right to dive in deeper what I'm interested at is diving into this function VFS right and for this I'm going to use the advance command pass in the function I want to advance to what this command will do is basically continue the execution until it arrives at this function now let's go ahead and run list over here and we can see that it does a bunch of stuff but I'm specifically interested in diving into this function new sync right because I want to continue diving deeper so I'm going to advance to here now from here on I'm going to fast forward the video cuz I want to focus on how this interacts in the end with the display on the lower level but it's basically more of the same stepping through the code and eventually arriving over there here I'm using by the way finish cuz I'm not interested in the hardw timer interrupt so I want to get past this code finish just goes until the end of the function by the way notice that we're now starting to step through driver code now I arrived at the function that is called conr this is getting pretty close to the code that is interacting with the lowlevel display and now notice over here on line 3010 we have the screen right W function this actually looks like a function but it's not a function we're going to see in a second this is a macro this is a macro that basically assigns this value into this place in memory so if I just run the frame command this is a GDB command that will show me where I'm currently at so we're at the VT driver file and let's advance to this line so I'm going to go to line 3010 now we're at the line with the macro over here as you can see over here I have the OS Dev Wiki open specifically on the text UI page let's go to the section here that talks about video mode you can see a popular choice for the video mode that is used when using VGA is VGA mode 3 and this allows direct memory access basically we write characters to memory and they're displayed on the screen it's pretty simple and we're going to mess a little with the colors and this is how it looks like with the colors also this line is important each character that is written takes two bytes of space in memory and we're going to see that in a second first bite is split into two segments this is related to the colors the for color and the back color second bite is just the asky value of the character so we're going to see that it correlates to the hello world that we're writing on the screen and we can easily modify the Colors by just modifying the second bite with numbers according to this table so we're going to play around with this a bit let's now go back to the code so I'm going to run here frame again and the interesting thing here is the TC variable you can see that this is passed into the the screen right W macro and this is written to this address in memory and we want to go ahead and modify the colors now this is not really helpful the fact that it's displayed in decimal so I'm going to print this in HEX I'm going to use for this the print command so print /x and then TC this is how this looks like in HEX now let's open up python for a [Applause] sec and let's check out the character of 48 in HEX and you can see that this is H this correlates with the H that we have in our hello world so now we know that this bite relates to the character so this bite must relate to the color now if we go here to the table we can see that seven correlates to gray so let's change this for example to Red so we're just going to put four over there but something funny sometimes you can change variables simply using GDB but in this case it's not going to let you we're going to see this like this for example if we assign this to be 448 instead of 748 in HEX GDB is not going to let us it's going to tell me that it's not L value it's probably because this variable is somehow optimized out we're going to have to dive in a little bit to the assembly first of all notice that I'm currently on this line so I can print out the current instruction I'm on by using x/i X is examine and I is instruction so I'm examining the current instruction by passing in dollar and then pc pc stands for program counter and you can see the current line I'm on is disassembly line Now default syntax over here of assembly is AT&T I don't really like AT&T syntax so I'm going to set this to Intel so I'm going to use set disassembly flavor and Intel now if I run the same command it'll be more fun to read now this only displays the current instruction I want to display a couple of the next instructions so I'm going to run instead of just I I'm going to use 10 I for example display the next 10 instructions I'm going to close here the python so the current line correlates to a couple of assembly instructions but notice that the only instruction in this area that actually writes something to memory is this line so we're going to advance into this line and modify the r10w register to do that I'm going to figure out the address of this line which is right over here on the left is the address in memory but this is the address that is more human readable going to use the advanc commands notice I'm going to put a star over here that is because we're talking about a memory address and paste this now if I take a look at the current instruction I'm on I'm on this instruction right over here so now I can go ahead and modify this register right before before it's writing this into the screen memory so I'm going to start by showing you what is currently inside of this register and it will look familiar by the way notice I'm proceeding registers with a dollar before this is a 748 that we saw before seven is the gray color and we're going to change this to Red how we're going to do that I'm going to change this seven to be four so I can use the same print except I can use equal sign over here and assign this to be whatever I want let's say 448 and now what I'm going to do is I'm going to put a break point on the same line I'm currently at by the way I can just use B to place break points I don't have to write break each time and I'm going to put a star over here cuz this is an address in memory and I'm just going to run continue to continue execution you can see that breakpoint was hit again but if I take a look at Linux right now you can see I indeed printed a character that is red so it worked this is really cool let's take a look at how we can make it green now so I'm going to do the same thing that we did four except instead of four I'm going to put here two now I'm going to run continue and now we got a green character same for blue so blue is one I just put in one and we have a blue character
Info
Channel: Nir Lichtman
Views: 30,027
Rating: undefined out of 5
Keywords:
Id: aAuw2EVCBBg
Channel Id: undefined
Length: 12min 45sec (765 seconds)
Published: Mon Jul 08 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.