KernelNewbies
  • Comments
  • Immutable Page
  • Menu
    • Navigation
    • RecentChanges
    • FindPage
    • Local Site Map
    • Help
    • HelpContents
    • HelpOnMoinWikiSyntax
    • Display
    • Attachments
    • Info
    • Raw Text
    • Print View
    • Edit
    • Load
    • Save
  • Login

Kernel Hacking

  • Frontpage

  • Kernel Hacking

  • Kernel Documentation

  • Kernel Glossary

  • FAQ

  • Found a bug?

  • Kernel Changelog

  • Upstream Merge Guide

Projects

  • KernelJanitors

  • KernelMentors

  • KernelProjects

Community

  • Why a community?

  • Regional Kernelnewbies

  • Personal Pages

  • Upcoming Events

References

  • Mailing Lists

  • Related Sites

  • Programming Links

Wiki

  • Recent Changes

  • Site Editors

  • Side Bar

  • Tips for Editors

  • Hosted by WikiWall

Navigation

  • RecentChanges
  • FindPage
  • HelpContents

Upload page content

You can upload content for the page named below. If you change the page name, you can also upload content for another page. If the page name is empty, we derive the page name from the file name.

File to load page content from
Page name
Comment

KernelNewbies:
  • Documents
  • CopyUser

At the heart of the code for copying data between kernel and user-space on x86, there is the macro __copy_user, which expands to some assembly as follows :

 #define __copy_user(to,from,size)     
do {         
 int __d0, __d1;       
 __asm__ __volatile__(      
  "0: rep; movsl\n"     
  " movl %3,%0\n"     
  "1: rep; movsb\n"     
  "2:\n"       
  ".section .fixup,\"ax\"\n"    
  "3: lea 0(%3,%0,4),%0\n"    
  " jmp 2b\n"     
  ".previous\n"      
  ".section __ex_table,\"a\"\n"    
  " .align 4\n"     
  " .long 0b,3b\n"     
  " .long 1b,2b\n"     
  ".previous"      
  : "=&c"(size), "=&D" (__d0), "=&S" (__d1)  
  : "r"(size & 3), "0"(size / 4), "1"(to), "2"(from) 
  : "memory");      
} while (0)

This is perhaps an intimidating few lines, so we here we go into more detail into the code. Don't forget to read the inline assembly links on this site.

Naive copy

  "0: rep; movsl\n"
  " movl %3,%0\n"
  "1: rep; movsb\n"
  "2:\n"

The first three lines naively copy 'size' bytes from 'from' to 'to'. I write "naively" because it might happen that the copy fails; then a memory exception would occur. A memory fault could occur for several reasons, each having their own way to handle the fault. The extra code used in '__copy_user' is one way to handle simple errors.

Fixup

  ".section .fixup,\"ax\"\n"
  "3: lea 0(%3,%0,4),%0\n"    
  " jmp 2b\n"

The kernel contains a table (in section '__ex_table') containing entries (X, Y) saying that if an error occurs at address X, then jump to address Y. The entries declared in the '__copy_user' code thus say that if a memory error occurs when executing the code at the label '0:', the handler should return to (and then execute) the code at the label '3:', calculating the actual number of non-copied bytes. Likewise, an error at '1:' makes the handler return to '2:', just skipping any more copying.

Note that lea 0(%3,%0,4),%0 is equivalent to the calculation %ecx = (size % 4) + %ecx * 4.

Labels like '0:', '1:', ... are "local labels", which can be used several times for different locations in the same code. They are then referenced by '0b', '1f', ... meaning "label 0 searching backwards" and "label 1 searching forwards" respectively.

Sections

  ".previous\n"

The assembler directive .previous just tells the assembler to put the following code/data in the section used before the current section, probably the .text section.

The exception table data is put into the __ex_table section used by all exception table code in the kernel.

Exception table

  ".section __ex_table,\"a\"\n"    
  " .align 4\n"     
  " .long 0b,3b\n"     
  " .long 1b,2b\n"     
  ".previous"      

The actual exception table itself in X,Y form, as described above.

Originally by Per Persson, modified by John Levon.


CategoryDocs

  • MoinMoin Powered
  • Python Powered
  • GPL licensed
  • Valid HTML 4.01