<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss version="2.0"><channel><title>Wei Chong's Blog</title><link>http://weichong78.blogspot.com/</link><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/WeiChongsBlog" /><description>Information from this blog is for my personal use only and may not accurately reflect anything and thus may not be cited or used for any official reference purposes.  I will not be liable for any error in the content or any action taken in reliance thereon. All copyrights and trademarks belong to their respective owner.  Should there be a conflict between my humble opinion/review with the original content author, it is most of the time due to my shallow understanding and mistake.</description><language>en</language><managingEditor>noreply@blogger.com (Wei Chong Tan)</managingEditor><lastBuildDate>Sun, 20 May 2012 23:09:00 PDT</lastBuildDate><generator>Blogger http://www.blogger.com</generator><openSearch:totalResults xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">138</openSearch:totalResults><openSearch:startIndex xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">1</openSearch:startIndex><openSearch:itemsPerPage xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">25</openSearch:itemsPerPage><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="weichongsblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><title>USB pendrive installer from DVD installer</title><link>http://weichong78.blogspot.com/2012/04/again-it-has-been-long-time-since-my.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Sat, 31 Mar 2012 19:17:35 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-5470389367394152255</guid><description>Again, it has been a long time since my last post.  :-)
This weekend I was trying to help my mom with her Linux Mint 12 installation.
So, I burnt an installer DVD for her, only to find out that her old laptop's DVD drive is not working any more. It just can't read the DVD.  Without downloading yet another USB pendrive image, I had to find a way to convert the installer DVD into a pendrive installer.

So, here is what I did:
&lt;br&gt;
1. Mount the DVD installer on my own laptop, which DVD drive is working and read the size (block count) using the df command:
&lt;div class="mycode"&gt;
[weichong@aspire4810tz ~]$ df 
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sr0         1052128 1052128         0 100% /media/Linux Mint 12 32-bit
&lt;/div&gt;
2. Use dd to extract the ISO from the DVD drive:
&lt;div class="mycode"&gt;
[weichong@aspire4810tz ~]$ dd if=/dev/sr0 of=./linuxmint12.iso bs=1024 count=1052128
&lt;/div&gt;
3. Use md5sum to verify that the ISO image is the same with the original ISO image in the distro website:
&lt;div class="mycode"&gt;
[weichong@aspire4810tz ~]$ md5sum ./Downloads/linuxmint12.iso 
ee3d6e2ca498bc7685b7f17cdb5f2eea  ./Downloads/linuxmint12.iso
&lt;/div&gt;
4. Plug a USB pendrive into my laptop (/dev/sdb1), and follow these steps &lt;a href="http://docs.fedoraproject.org/en-US/Fedora/16/html/Installation_Guide/Making_USB_Media-UNIX_Linux.html"&gt;here&lt;/a&gt; to produce a bootable pendrive:
&lt;div class="mycode"&gt;
[weichong@aspire4810tz ~]$ su -c 'livecd-iso-to-disk ./Downloads/linuxmin12.iso /dev/sdb1'
&lt;/div&gt;
5. Copy all the content from the mounted DVD drive to the pendrive (/media/LIVE):
&lt;div class="mycode"&gt;
[weichong@aspire4810tz ~]$ cp -R /media/Linux\ Mint\ 12\ 32-bit/* /media/LIVE/
&lt;/div&gt;
6. Plug in this USB pendrive to my mom's laptop and boot from there.

Note that the steps described here an account I try to recall.  Hopefully, I didn't recall anything wrongly by mistake.  If I  do, hehe, this is April fool's joke. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-5470389367394152255?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-01T10:17:35.376+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Patch to build OpenCV 2.3.0 with ffmpeg</title><link>http://weichong78.blogspot.com/2011/07/patch-to-build-opencv-230-with-ffmpeg.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Thu, 14 Jul 2011 06:38:05 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-6449401523256775620</guid><description>It has been ages I have not update my blog at all.  Partly due to busy schedule, and partly due to laziness :P&lt;br /&gt;
Lately I am trying out OpenCV on my Ubuntu 10.04 LTS box.&lt;br /&gt;
Due to some issue in the old pre built libcv-dev with v4l2 which cause the webcam not able to work properly without PRELOAD=/usr/lib/libv4l/v4l1compat.so, I tried to build my own OpenCV 2.3.0 and ffmpeg from source.&lt;br /&gt;
However, I realize that OpenCV 2.3.0 still have not keep up with the latest changes in ffmpeg.  So, I either have to content with using the ffmpeg that comes with the OpenCV source, or I have to patch it to work.  I chose that later as I wanted it to use my custom ffmpeg.&lt;br /&gt;
Thinking that it might benefits other I try to post it here, just in case:&lt;br /&gt;
&lt;div class="mycode"&gt;Index: OpenCV-2.3.0/modules/highgui/src/cap_ffmpeg_impl.hpp&lt;br /&gt;
===================================================================&lt;br /&gt;
--- OpenCV-2.3.0.orig/modules/highgui/src/cap_ffmpeg_impl.hpp 2011-07-10 11:26:54.000000000 +0800&lt;br /&gt;
+++ OpenCV-2.3.0/modules/highgui/src/cap_ffmpeg_impl.hpp 2011-07-10 11:50:15.000000000 +0800&lt;br /&gt;
@@ -135,7 +135,13 @@&lt;br /&gt;
 #define PIX_FMT_RGBA32 PIX_FMT_RGB32&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
+#ifndef CODEC_TYPE_VIDEO&lt;br /&gt;
+#define CODEC_TYPE_VIDEO      AVMEDIA_TYPE_VIDEO&lt;br /&gt;
+#endif&lt;br /&gt;
 &lt;br /&gt;
+#ifndef PKT_FLAG_KEY&lt;br /&gt;
+#define PKT_FLAG_KEY AV_PKT_FLAG_KEY&lt;br /&gt;
+#endif&lt;br /&gt;
 &lt;br /&gt;
 char * FOURCC2str( int fourcc )&lt;br /&gt;
 {&lt;br /&gt;
@@ -550,7 +556,7 @@&lt;br /&gt;
 &lt;br /&gt;
     // First time we're called, set packet.data to NULL to indicate it&lt;br /&gt;
     // doesn't have to be freed&lt;br /&gt;
-    if (bFirstTime) {&lt;br /&gt;
+    if (bFirstTime) { &lt;br /&gt;
         bFirstTime = false;&lt;br /&gt;
         packet.data = NULL;&lt;br /&gt;
     }&lt;br /&gt;
@@ -561,7 +567,7 @@&lt;br /&gt;
     // free last packet if exist&lt;br /&gt;
     if (packet.data != NULL) {&lt;br /&gt;
         av_free_packet (&amp;packet);&lt;br /&gt;
-    }&lt;br /&gt;
+    } &lt;br /&gt;
 &lt;br /&gt;
     // get the next frame&lt;br /&gt;
     while (!valid) {&lt;br /&gt;
@@ -574,17 +580,20 @@&lt;br /&gt;
   if( packet.stream_index != video_stream ) {&lt;br /&gt;
           av_free_packet (&amp;packet);&lt;br /&gt;
           continue;&lt;br /&gt;
-      }&lt;br /&gt;
+       }&lt;br /&gt;
 &lt;br /&gt;
-#if LIBAVFORMAT_BUILD &gt; 4628&lt;br /&gt;
-        avcodec_decode_video(video_st-&gt;codec,&lt;br /&gt;
-                             picture, &amp;got_picture,&lt;br /&gt;
-                             packet.data, packet.size);&lt;br /&gt;
-#else&lt;br /&gt;
-        avcodec_decode_video(&amp;video_st-&gt;codec,&lt;br /&gt;
-                             picture, &amp;got_picture,&lt;br /&gt;
-                             packet.data, packet.size);&lt;br /&gt;
-#endif&lt;br /&gt;
+//#if LIBAVFORMAT_BUILD &gt; 4628&lt;br /&gt;
+//        avcodec_decode_video(video_st-&gt;codec,&lt;br /&gt;
+//                             picture, &amp;got_picture,&lt;br /&gt;
+//                             packet.data, packet.size);&lt;br /&gt;
+//#else&lt;br /&gt;
+//        avcodec_decode_video(&amp;video_st-&gt;codec,&lt;br /&gt;
+//                             picture, &amp;got_picture,&lt;br /&gt;
+//                             packet.data, packet.size);&lt;br /&gt;
+//#endif&lt;br /&gt;
+avcodec_decode_video2(video_st-&gt;codec,&lt;br /&gt;
+                        picture, &amp;got_picture,&lt;br /&gt;
+                        &amp;packet);&lt;br /&gt;
 &lt;br /&gt;
         if (got_picture) {&lt;br /&gt;
             // we have a new picture, so memorize it&lt;br /&gt;
@@ -825,16 +834,16 @@&lt;br /&gt;
 static const char * icvFFMPEGErrStr(int err)&lt;br /&gt;
 {&lt;br /&gt;
     switch(err) {&lt;br /&gt;
-    case AVERROR_NUMEXPECTED:&lt;br /&gt;
-  return "Incorrect filename syntax";&lt;br /&gt;
+//    case AVERROR_NUMEXPECTED:&lt;br /&gt;
+//  return "Incorrect filename syntax";&lt;br /&gt;
     case AVERROR_INVALIDDATA:&lt;br /&gt;
   return "Invalid data in header";&lt;br /&gt;
-    case AVERROR_NOFMT:&lt;br /&gt;
-  return "Unknown format";&lt;br /&gt;
-    case AVERROR_IO:&lt;br /&gt;
-  return "I/O error occurred";&lt;br /&gt;
-    case AVERROR_NOMEM:&lt;br /&gt;
-  return "Memory allocation error";&lt;br /&gt;
+//    case AVERROR_NOFMT:&lt;br /&gt;
+//  return "Unknown format";&lt;br /&gt;
+//    case AVERROR_IO:&lt;br /&gt;
+//  return "I/O error occurred";&lt;br /&gt;
+//    case AVERROR_NOMEM:&lt;br /&gt;
+//  return "Memory allocation error";&lt;br /&gt;
     default:&lt;br /&gt;
   break;&lt;br /&gt;
     }&lt;br /&gt;
@@ -1237,7 +1246,7 @@&lt;br /&gt;
  av_register_all ();&lt;br /&gt;
 &lt;br /&gt;
  /* auto detect the output format from the name and fourcc code. */&lt;br /&gt;
- fmt = guess_format(NULL, filename, NULL);&lt;br /&gt;
+ fmt = av_guess_format(NULL, filename, NULL);&lt;br /&gt;
  if (!fmt)&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
@@ -1260,7 +1269,7 @@&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
     // alloc memory for context&lt;br /&gt;
- oc = av_alloc_format_context();&lt;br /&gt;
+ oc = avformat_alloc_context();&lt;br /&gt;
  assert (oc);&lt;br /&gt;
 &lt;br /&gt;
  /* set file name */&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
By the way, for those who intend to build OpenCV 2.2.0 instead, patches already exist &lt;a href="http://esimaging.co.uk/index.php/resources/case-studies/81-building-latest-opencv-with-svn-ffmpeg-on-ubuntu-1004-and-1104"&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Hope it helps.  Enjoy! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-6449401523256775620?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-14T21:38:05.777+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total></item><item><title>tty anyone? reading serially...</title><link>http://weichong78.blogspot.com/2010/05/tty-anyone-reading-serially.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Fri, 28 May 2010 05:30:42 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-4123456798309543331</guid><description>&lt;a href="http://en.wikipedia.org/wiki/Text_terminal"&gt;Text terminal&lt;/a&gt; (and of course, &lt;a href="http://en.wikipedia.org/wiki/Computer_console"&gt;console&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Pseudo_terminal"&gt;pseudo-terminal&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Virtual_console_%28computer_user-interface%29"&gt;virtual console&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Terminal_emulator"&gt;terminal emulator&lt;/a&gt;) or TTY (&lt;a href="http://en.wikipedia.org/wiki/Teleprinter"&gt;teletype printer&lt;/a&gt;) as it is usually called, due to historical reason, is something any average Linux/UNIX user would use on a daily basis, in one form or another.&lt;br /&gt;
Its internal mechanism is indeed something that has always catch my attention and curiosity. Since today is a holiday, I took some time off to trace the code behind the serial interface (like ttyS0). Below is what I learn...(or so I think).&lt;br /&gt;
&lt;br /&gt;
Before diving deep into the rest of the source, lets look at some definition.&lt;br /&gt;
&lt;div class="mycode"&gt;#include/linux/serial_reg.h:&lt;br /&gt;
#define UART_RX         0       /* In:  Receive buffer */&lt;br /&gt;
#define UART_LSR        5       /* In:  Line Status Register */&lt;br /&gt;
#define UART_LSR_BI             0x10 /* Break interrupt indicator */&lt;br /&gt;
#define UART_LSR_DR             0x01 /* Receiver data ready */&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
And also the central structure tty_struct, which due to history reason, also include data for the line discipline.&lt;br /&gt;
&lt;div class="mycode"&gt;#include/linux/tty.h:&lt;br /&gt;
struct tty_struct {&lt;br /&gt;
...&lt;br /&gt;
        struct tty_ldisc *ldisc;&lt;br /&gt;
...&lt;br /&gt;
        struct tty_bufhead buf;&lt;br /&gt;
...&lt;br /&gt;
        wait_queue_head_t read_wait;&lt;br /&gt;
...&lt;br /&gt;
         * The following is data for the N_TTY line discipline.  For&lt;br /&gt;
         * historical reasons, this is included in the tty structure.&lt;br /&gt;
...&lt;br /&gt;
        char *read_buf;&lt;br /&gt;
...&lt;br /&gt;
        struct tty_port *port;&lt;br /&gt;
};&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
When there are data on the serial (UART) interface, and the interrupt is trigger, the interrupt service routine serial8250_interrupt() is invoked.&lt;br /&gt;
&lt;div class="mycode"&gt;drivers/serial/8250.c:&lt;br /&gt;
static irqreturn_t serial8250_interrupt(int irq, void *dev_id)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
                if (!(iir &amp; UART_IIR_NO_INT)) {&lt;br /&gt;
                        serial8250_handle_port(up);&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void serial8250_handle_port(struct uart_8250_port *up)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
        if (status &amp; (UART_LSR_DR | UART_LSR_BI))&lt;br /&gt;
                receive_chars(up, &amp;status);&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void&lt;br /&gt;
receive_chars(struct uart_8250_port *up, unsigned int *status)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
        do {&lt;br /&gt;
                if (likely(lsr &amp; UART_LSR_DR))&lt;br /&gt;
                        ch = serial_inp(up, UART_RX);&lt;br /&gt;
...&lt;br /&gt;
                uart_insert_char(&amp;up-&gt;port, lsr, UART_LSR_OE, ch, flag);&lt;br /&gt;
&lt;br /&gt;
ignore_char:&lt;br /&gt;
                lsr = serial_inp(up, UART_LSR);&lt;br /&gt;
        } while ((lsr &amp; (UART_LSR_DR | UART_LSR_BI)) &amp;&amp; (max_count-- &gt; 0));&lt;br /&gt;
...&lt;br /&gt;
        tty_flip_buffer_push(tty);&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&lt;/div&gt;&lt;div class="mycode"&gt;#include/linux/serial_core.h:&lt;br /&gt;
static inline void&lt;br /&gt;
uart_insert_char(struct uart_port *port, unsigned int status,&lt;br /&gt;
                 unsigned int overrun, unsigned int ch, unsigned int flag)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
                tty_insert_flip_char(tty, ch, flag);&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
From the interrupt service routine, the callee will eventually copy the data to the corresponding tty_buffer.&lt;br /&gt;
&lt;div class="mycode"&gt;#include/linux/tty_flip.h:&lt;br /&gt;
static inline int tty_insert_flip_char(struct tty_struct *tty,&lt;br /&gt;
                                        unsigned char ch, char flag)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
        struct tty_buffer *tb = tty-&gt;buf.tail;&lt;br /&gt;
...&lt;br /&gt;
                tb-&gt;char_buf_ptr[tb-&gt;used++] = ch;&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
Then, the data is push/flush to the corresponding line discipline.&lt;br /&gt;
&lt;div class="mycode"&gt;drivers/char/tty_buffer.c:&lt;br /&gt;
 *      Queue a push of the terminal flip buffers to the line discipline. This&lt;br /&gt;
void tty_flip_buffer_push(struct tty_struct *tty)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
        if (tty-&gt;low_latency)&lt;br /&gt;
                flush_to_ldisc(&amp;tty-&gt;buf.work.work); &lt;br /&gt;
        else&lt;br /&gt;
                schedule_delayed_work(&amp;tty-&gt;buf.work, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void flush_to_ldisc(struct work_struct *work)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
        struct tty_ldisc *disc;&lt;br /&gt;
...&lt;br /&gt;
                        disc-&gt;ops-&gt;receive_buf(tty, char_buf,&lt;br /&gt;
                                                        flag_buf, count);&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&lt;/div&gt;&lt;div class="mycode"&gt;#include/linux/tty_ldisc.h:&lt;br /&gt;
struct tty_ldisc_ops {&lt;br /&gt;
...&lt;br /&gt;
        /*&lt;br /&gt;
         * The following routines are called from below.&lt;br /&gt;
         */&lt;br /&gt;
        void    (*receive_buf)(struct tty_struct *, const unsigned char *cp,&lt;br /&gt;
                               char *fp, int count);&lt;br /&gt;
        void    (*write_wakeup)(struct tty_struct *);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
struct tty_ldisc {&lt;br /&gt;
        struct tty_ldisc_ops *ops;&lt;br /&gt;
...&lt;br /&gt;
};&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
The line discipline's receive_buf hook will copy the data to its own read buffer and wake up the process that is waiting (sleeping) for the incoming data.&lt;br /&gt;
&lt;div class="mycode"&gt;drivers/char/n_tty.c:&lt;br /&gt;
 *      Called by the terminal driver when a block of characters has&lt;br /&gt;
 *      been received. This function must be called from soft contexts&lt;br /&gt;
 *      not from interrupt context. The driver is responsible for making&lt;br /&gt;
 *      calls one at a time and in order (or using flush_to_ldisc)&lt;br /&gt;
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,&lt;br /&gt;
                              char *fp, int count)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
                memcpy(tty-&gt;read_buf + tty-&gt;read_head, cp, i);&lt;br /&gt;
...&lt;br /&gt;
        if (!tty-&gt;icanon &amp;&amp; (tty-&gt;read_cnt &gt;= tty-&gt;minimum_to_wake)) {&lt;br /&gt;
                kill_fasync(&amp;tty-&gt;fasync, SIGIO, POLL_IN);&lt;br /&gt;
                if (waitqueue_active(&amp;tty-&gt;read_wait))&lt;br /&gt;
                        wake_up_interruptible(&amp;tty-&gt;read_wait);&lt;br /&gt;
        }&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct tty_ldisc_ops tty_ldisc_N_TTY = {&lt;br /&gt;
...&lt;br /&gt;
        .receive_buf     = n_tty_receive_buf,&lt;br /&gt;
...&lt;br /&gt;
};&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
And that is how the program (like the bash shell that is running on ttyS0) receive the data!&lt;br /&gt;
Or at least that is what I think how it all works.&lt;br /&gt;
If time permits, it would be great to continue digging into how write operation works on ttyS0, and other "terminals" like pty etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-4123456798309543331?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-28T20:30:42.627+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>vmware, qemu and gdb for boot time real mode debugging</title><link>http://weichong78.blogspot.com/2010/04/vmware-qemu-and-gdb-for-boot-time-real.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Sat, 17 Apr 2010 21:37:17 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-3786017816356414879</guid><description>I kinda like vmware&lt;iframe align="right" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=weisbl-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0596157258&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt; (for its speed and support of a more recent virtual hardware then the default qemu one) but all these while I favor qemu over vmware when it comes to kernel debugging since qemu let me inspect the state of the guest OS execution.&lt;br /&gt;
&lt;br /&gt;
This is especially true when it comes to early boot time debugging on stuff like boot loaders where I need to guest system to halt for remote debugger as early as possible, using options such as &lt;br /&gt;
&lt;div class="mycode"&gt;&lt;br /&gt;
qemu -s -S -cpu coreduo /path/to/my/guestos.qcow2&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
Note that, to break very early at boot loader (or earlier) stage, at addresses such as 0x7c00, we need to boot the kernel off the target guestos.qcow2, and not using option like this one, since (I think) qemu would bypass the boot loader stage and go straight to boot the kernel.&lt;br /&gt;
&lt;div class="mycode"&gt;&lt;br /&gt;
qemu -s -S -cpu coreduo -kernel arch/x86/boot/bzImage -append "init=/bin/bash root=/dev/sda1" /path/to/my/guestos.qcow2&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
However, today I found out that vmware too, have awesome capability to allow me to halt the guest system for remote gdb connection, as early as the reboot vector in real mode!&lt;br /&gt;
All I have to do is to add the below option to my VMX config file:&lt;br /&gt;
&lt;div class="mycode"&gt;&lt;br /&gt;
debugStub.listen.guest32 = "TRUE"&lt;br /&gt;
debugStub.listen.guest32.remote = "TRUE"&lt;br /&gt;
monitor.debugOnStartGuest32 = "TRUE"&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
To connect to a qemu system, the gdb port to use is:&lt;br /&gt;
&lt;div class="mycode"&gt;&lt;br /&gt;
target remote localhost:1234&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
For vmware, it is:&lt;br /&gt;
&lt;div class="mycode"&gt;&lt;br /&gt;
target remote localhost:8832&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
Finally, I also learn that gdb can switch architecture, which is useful when debugging x86 guest system early in boot time, where there are real mode codes and later with protected mode code, using the commands below:&lt;br /&gt;
&lt;div class="mycode"&gt;&lt;br /&gt;
set architecture i8086&lt;br /&gt;
set architecture i386&lt;/div&gt;&lt;br /&gt;
&lt;script src="http://www.assoc-amazon.com/s/link-enhancer?tag=weisbl-20&amp;amp;o=1" type="text/javascript"&gt;
&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-3786017816356414879?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-18T12:37:17.391+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Reading MSR</title><link>http://weichong78.blogspot.com/2010/04/reading-msr.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Fri, 09 Apr 2010 16:21:56 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-8939356957448200679</guid><description>Lately, I have been playing with the msr-tools utility rdmsr and wrmsr.&lt;br /&gt;They are really convenient.&lt;br /&gt;However, it is not so convenient when I have to play with bitwise or and bitwise and manipulation.&lt;br /&gt;So, I use strace to observe how the rdmsr utility do its job.&lt;br /&gt;Additionally, I read the source of linux/arch/x86/kernel/msr.c to understand how /dev/cpu/0/msr behaves.&lt;br /&gt;Looks like the msr driver just use the lseek() system call to adjust the "offset", brilliant.&lt;br /&gt;After that I just try to reinvent the wheel and write my own rdmsr in C.&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;#include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/ioctl.h&amp;gt;&lt;br /&gt;&lt;br /&gt;/* Arbitrarily choose any MSR from linux/arch/x86/include/asm/msr-index.h, in this case MSR_IA32_PERF_STATUS */&lt;br /&gt;#define REG_ADDR 0x198&lt;br /&gt;&lt;br /&gt;int main ()&lt;br /&gt;{&lt;br /&gt; int fd = 0;&lt;br /&gt; off_t of = 0;&lt;br /&gt; ssize_t sz = 0;&lt;br /&gt; unsigned long long int msr = 0;&lt;br /&gt;&lt;br /&gt; fd = open("/dev/cpu/0/msr", O_RDWR);&lt;br /&gt; if (!fd) {&lt;br /&gt;  perror("open /dev/cpu/0/msr fail\n");&lt;br /&gt;  return -1;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; of = lseek(fd, REG_ADDR, SEEK_SET); &lt;br /&gt; sz = read(fd, &amp;msr, sizeof(msr));&lt;br /&gt; printf("MSR %x = %llx\n", REG_ADDR, msr);&lt;br /&gt;&lt;br /&gt; close(fd);&lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-8939356957448200679?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-10T07:21:56.066+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>yum install from media.repo in Fedora installer CD</title><link>http://weichong78.blogspot.com/2010/04/yum-install-from-mediarepo-in-fedora.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Wed, 07 Apr 2010 17:37:15 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-5383465688773112174</guid><description>Disclaimer: I'm pretty newbie in the YUM/RPM world, so there might already be a better way to do this out there.&lt;br /&gt;&lt;br /&gt;Usually, for shorter install time, I choose only the minimal package during the installation.  I will then install more packages using the yum install after the system boots.&lt;br /&gt;&lt;br /&gt;This is usually not a problem when the network is fast enough and I actually want to get the latest and greatest package from the remote YUM repository.&lt;br /&gt;&lt;br /&gt;However, this becomes a problem when:&lt;br /&gt;1. Network is unavailable for the new system.&lt;br /&gt;2. I just want to have the exact same snapshot of RPM with the installer CD/DVD.&lt;br /&gt;&lt;br /&gt;After playing around. I found this workaround:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;# mount /dev/cdrom /media&lt;br /&gt;# cp /media/media.repo /etc/yum.repos.d/&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Then, add this line to /etc/yum.repos.d/media.repo under the [InstallMedia] section:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;baseurl=file:///media/&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The above line will enable YUM to locate /media/repodata/ for things like /media/repodata/repomd.xml.&lt;br /&gt;&lt;br /&gt;Finally, one can do the usual yum install (to get, say xorg-x11-server-Xorg) with the cdrom still mounted to /media:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;# yum install xorg-x11-server-Xorg&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-5383465688773112174?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-08T08:37:15.761+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total></item><item><title>page fault and block device, part 3</title><link>http://weichong78.blogspot.com/2010/04/page-fault-and-block-device-part-3.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Tue, 06 Apr 2010 05:40:20 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-6274371274572719343</guid><description>Just for the fun of tracing a running system while studying about page fault, I setup a qemu system to be debug via gdb.  I chose to break the system at mpage_end_io_read() which gets call upon completion for waking up the process.&lt;br /&gt;&lt;br /&gt;I executed grep upon reboot, so that the program is page fault for the 1st time.&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;root@(none)/# ls /bin/ | grep grep&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;As expected, gdb breaks at mpage_end_io_read() with the below backtrace:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;#0  mpage_end_io_read (bio=0xc79c4380, err=0) at fs/mpage.c:45&lt;br /&gt;#1  0xc10c0a8f in bio_endio (bio=0xc79c4380, error=0) at fs/bio.c:1431&lt;br /&gt;#2  0xc1121128 in req_bio_endio (rq=0xc7983708, bio=0xc79c4380, nbytes=&lt;value optimized out&gt;, error=0) at block/blk-core.c:160&lt;br /&gt;#3  0xc112126c in blk_update_request (req=0xc7983708, error=&lt;value optimized out&gt;, nr_bytes=&lt;value optimized out&gt;) at block/blk-core.c:1976&lt;br /&gt;#4  0xc1121407 in blk_update_bidi_request (rq=0xc79c4380, error=0, nr_bytes=3238806812, bidi_bytes=0) at block/blk-core.c:2077&lt;br /&gt;#5  0xc1121d5b in blk_end_bidi_request (rq=0xc79c4380, error=0, nr_bytes=3238806812, bidi_bytes=0) at block/blk-core.c:2140&lt;br /&gt;#6  0xc1121dc7 in blk_end_request (rq=0xc79c4380, error=0, nr_bytes=3238806812) at block/blk-core.c:2192&lt;br /&gt;#7  0xc11e9883 in scsi_end_request (cmd=0xc795f900, good_bytes=&lt;value optimized out&gt;) at drivers/scsi/scsi_lib.c:548&lt;br /&gt;#8  scsi_io_completion (cmd=0xc795f900, good_bytes=&lt;value optimized out&gt;) at drivers/scsi/scsi_lib.c:795&lt;br /&gt;#9  0xc11e4a42 in scsi_finish_command (cmd=0xc795f900) at drivers/scsi/scsi.c:849&lt;br /&gt;#10 0xc11e9bbc in scsi_softirq_done (rq=&lt;value optimized out&gt;) at drivers/scsi/scsi_lib.c:1444&lt;br /&gt;#11 0xc1126375 in blk_done_softirq (h=&lt;value optimized out&gt;) at block/blk-softirq.c:34&lt;br /&gt;#12 0xc1033313 in __do_softirq () at kernel/softirq.c:219&lt;br /&gt;#13 0xc10333da in do_softirq () at kernel/softirq.c:266&lt;br /&gt;#14 0xc10334d7 in irq_exit () at kernel/softirq.c:303&lt;br /&gt;#15 0xc101534a in smp_apic_timer_interrupt (regs=&lt;value optimized out&gt;) at arch/x86/kernel/apic/apic.c:826&lt;br /&gt;#16 0xc1247b9a in ?? () at /home/weichong78/Development/tar/linux-2.6.34-rc3/arch/x86/include/asm/entry_arch.h:48&lt;br /&gt;#17 0xc11e44c8 in spin_unlock_irqrestore (lock=0xc79c4380, flags=0) at include/linux/spinlock.h:339&lt;br /&gt;#18 0xc11e4b87 in scsi_dispatch_cmd (cmd=0xc795f900) at drivers/scsi/scsi.c:752&lt;br /&gt;#19 0xc11e8fd3 in scsi_request_fn (q=0xc79a0000) at drivers/scsi/scsi_lib.c:1559&lt;br /&gt;#20 0xc11225c4 in __generic_unplug_device (q=0xc79a0000) at block/blk-core.c:265&lt;br /&gt;#21 0xc11227d6 in generic_unplug_device (q=0xc79a0000) at block/blk-core.c:283&lt;br /&gt;#22 0xc111efd2 in blk_unplug_work (work=&lt;value optimized out&gt;) at block/blk-core.c:303&lt;br /&gt;#23 0xc103f72b in run_workqueue (__cwq=&lt;value optimized out&gt;) at kernel/workqueue.c:403&lt;br /&gt;#24 worker_thread (__cwq=&lt;value optimized out&gt;) at kernel/workqueue.c:445&lt;br /&gt;#25 0xc1042577 in kthread (_create=0xc783ff24) at kernel/kthread.c:78&lt;br /&gt;#26 0xc1002cb6 in ?? () at arch/x86/kernel/entry_32.S:1051&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The code for mpage_end_io_read() is like this:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;static void mpage_end_io_read(struct bio *bio, int err)&lt;br /&gt;{               &lt;br /&gt;...&lt;br /&gt;                struct page *page = bvec-&gt;bv_page;&lt;br /&gt;...&lt;br /&gt;                unlock_page(page);&lt;br /&gt;...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So, by stepping the code until after *page is initialized, I can examine its value.&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;(gdb) display page&lt;br /&gt;1: page = &lt;value optimized out&gt;&lt;br /&gt;(gdb) next&lt;br /&gt;50   if (--bvec &gt;= bio-&gt;bi_io_vec)&lt;br /&gt;1: page = (struct page *) 0xc14fafa0&lt;br /&gt;(gdb) print *((struct page*)0xc14fafa0)&lt;br /&gt;$1 = {&lt;br /&gt;  flags = 1073872929, &lt;br /&gt;  _count = {&lt;br /&gt;    counter = 1&lt;br /&gt;  }, &lt;br /&gt;  {&lt;br /&gt;    _mapcount = {&lt;br /&gt;      counter = -1&lt;br /&gt;    }, &lt;br /&gt;    {&lt;br /&gt;      inuse = 65535, &lt;br /&gt;      objects = 65535&lt;br /&gt;    }&lt;br /&gt;  }, &lt;br /&gt;  {&lt;br /&gt;    {&lt;br /&gt;      private = 0, &lt;br /&gt;      mapping = 0xc7474148&lt;br /&gt;    }, &lt;br /&gt;    ptl = {&lt;br /&gt;      {&lt;br /&gt;        rlock = {&lt;br /&gt;          raw_lock = {&lt;br /&gt;            slock = 0&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }, &lt;br /&gt;    slab = 0x0, &lt;br /&gt;    first_page = 0x0&lt;br /&gt;  }, &lt;br /&gt;  {&lt;br /&gt;    index = 3, &lt;br /&gt;    freelist = 0x3&lt;br /&gt;  }, &lt;br /&gt;  lru = {&lt;br /&gt;    next = 0xc14f8cf8, &lt;br /&gt;    prev = 0xc13bc714&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The definition of struct page is:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;struct page {&lt;br /&gt;...&lt;br /&gt;                struct address_space *mapping;&lt;br /&gt;...&lt;br /&gt;};&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So, using gdb to cast mapping = 0xc7474148 as struct address_space*, we can see that&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;(gdb) print (struct address_space)*0xc7474148&lt;br /&gt;$2 = {&lt;br /&gt;  host = 0xc747409c, &lt;br /&gt;  page_tree = {&lt;br /&gt;    height = 1, &lt;br /&gt;    gfp_mask = 32, &lt;br /&gt;    rnode = 0xc747dce9&lt;br /&gt;  }, &lt;br /&gt;  tree_lock = {&lt;br /&gt;    {&lt;br /&gt;      rlock = {&lt;br /&gt;        raw_lock = {&lt;br /&gt;          slock = 1028&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }, &lt;br /&gt;  i_mmap_writable = 0, &lt;br /&gt;  i_mmap = {&lt;br /&gt;    prio_tree_node = 0x0, &lt;br /&gt;    index_bits = 1, &lt;br /&gt;    raw = 1&lt;br /&gt;  }, &lt;br /&gt;  i_mmap_nonlinear = {&lt;br /&gt;    next = 0xc7474168, &lt;br /&gt;    prev = 0xc7474168&lt;br /&gt;  }, &lt;br /&gt;  i_mmap_lock = {&lt;br /&gt;    {&lt;br /&gt;      rlock = {&lt;br /&gt;        raw_lock = {&lt;br /&gt;          slock = 0&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }, &lt;br /&gt;  truncate_count = 0, &lt;br /&gt;  nrpages = 4, &lt;br /&gt;  writeback_index = 0, &lt;br /&gt;  a_ops = 0xc125f494, &lt;br /&gt;  flags = 131290, &lt;br /&gt;  backing_dev_info = 0xc79a00b8, &lt;br /&gt;  private_lock = {&lt;br /&gt;    {&lt;br /&gt;      rlock = {&lt;br /&gt;        raw_lock = {&lt;br /&gt;          slock = 0&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }, &lt;br /&gt;  private_list = {&lt;br /&gt;    next = 0xc7474190, &lt;br /&gt;    prev = 0xc7474190&lt;br /&gt;  }, &lt;br /&gt;  assoc_mapping = 0x0&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The definition of struct address_space is:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;struct address_space {&lt;br /&gt;        struct inode            *host;          /* owner: inode, block_device */&lt;br /&gt;...&lt;br /&gt;};&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;From there, we can find out which file (more precisely, inode) is this completion about:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;(gdb) print (struct inode)*0xc747409c&lt;br /&gt;$3 = {&lt;br /&gt;  i_hash = {&lt;br /&gt;    next = 0x0, &lt;br /&gt;    pprev = 0xc15d43c8&lt;br /&gt;  }, &lt;br /&gt;  i_list = {&lt;br /&gt;    next = 0xc74652d8, &lt;br /&gt;    prev = 0xc139bf8c&lt;br /&gt;  }, &lt;br /&gt;  i_sb_list = {&lt;br /&gt;    next = 0xc747bdb4, &lt;br /&gt;    prev = 0xc798ce74&lt;br /&gt;  }, &lt;br /&gt;  i_dentry = {&lt;br /&gt;    next = 0xc74726a4, &lt;br /&gt;    prev = 0xc74726a4&lt;br /&gt;  }, &lt;br /&gt;  i_ino = 186584, &lt;br /&gt;  i_count = {&lt;br /&gt;    counter = 1&lt;br /&gt;  }, &lt;br /&gt;  i_nlink = 1, &lt;br /&gt;  i_uid = 0, &lt;br /&gt;  i_gid = 0, &lt;br /&gt;  i_rdev = 0, &lt;br /&gt;  i_blkbits = 12, &lt;br /&gt;  i_version = 1, &lt;br /&gt;  i_size = 100468, &lt;br /&gt;  i_size_seqcount = {&lt;br /&gt;    sequence = 0&lt;br /&gt;  }, &lt;br /&gt;  i_atime = {&lt;br /&gt;    tv_sec = 1270473948, &lt;br /&gt;    tv_nsec = 0&lt;br /&gt;  }, &lt;br /&gt;  i_mtime = {&lt;br /&gt;    tv_sec = 1220202404, &lt;br /&gt;    tv_nsec = 0&lt;br /&gt;  }, &lt;br /&gt;  i_ctime = {&lt;br /&gt;    tv_sec = 1238493459, &lt;br /&gt;    tv_nsec = 0&lt;br /&gt;  }, &lt;br /&gt;  i_blocks = 208, &lt;br /&gt;  i_bytes = 0, &lt;br /&gt;  i_mode = 33261, &lt;br /&gt;  i_lock = {&lt;br /&gt;    {&lt;br /&gt;      rlock = {&lt;br /&gt;        raw_lock = {&lt;br /&gt;          slock = 257&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }, &lt;br /&gt;  i_mutex = {&lt;br /&gt;    count = {&lt;br /&gt;      counter = 1&lt;br /&gt;    }, &lt;br /&gt;    wait_lock = {&lt;br /&gt;      {&lt;br /&gt;        rlock = {&lt;br /&gt;          raw_lock = {&lt;br /&gt;            slock = 0&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }, &lt;br /&gt;    wait_list = {&lt;br /&gt;      next = 0xc7474118, &lt;br /&gt;      prev = 0xc7474118&lt;br /&gt;    }, &lt;br /&gt;    owner = 0x0&lt;br /&gt;  }, &lt;br /&gt;  i_alloc_sem = {&lt;br /&gt;    count = 0, &lt;br /&gt;    wait_lock = {&lt;br /&gt;      {&lt;br /&gt;        rlock = {&lt;br /&gt;          raw_lock = {&lt;br /&gt;            slock = 0&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }, &lt;br /&gt;    wait_list = {&lt;br /&gt;      next = 0xc747412c, &lt;br /&gt;      prev = 0xc747412c&lt;br /&gt;    }&lt;br /&gt;  }, &lt;br /&gt;  i_op = 0xc125f2c0, &lt;br /&gt;  i_fop = 0xc125f258, &lt;br /&gt;  i_sb = 0xc798ce00, &lt;br /&gt;  i_flock = 0x0, &lt;br /&gt;  i_mapping = 0xc7474148, &lt;br /&gt;  i_data = {&lt;br /&gt;    host = 0xc747409c, &lt;br /&gt;    page_tree = {&lt;br /&gt;      height = 1, &lt;br /&gt;      gfp_mask = 32, &lt;br /&gt;      rnode = 0xc747dce9&lt;br /&gt;    }, &lt;br /&gt;    tree_lock = {&lt;br /&gt;      {&lt;br /&gt;        rlock = {&lt;br /&gt;          raw_lock = {&lt;br /&gt;            slock = 1028&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }, &lt;br /&gt;    i_mmap_writable = 0, &lt;br /&gt;    i_mmap = {&lt;br /&gt;      prio_tree_node = 0x0, &lt;br /&gt;      index_bits = 1, &lt;br /&gt;      raw = 1&lt;br /&gt;    }, &lt;br /&gt;    i_mmap_nonlinear = {&lt;br /&gt;      next = 0xc7474168, &lt;br /&gt;      prev = 0xc7474168&lt;br /&gt;    }, &lt;br /&gt;    i_mmap_lock = {&lt;br /&gt;      {&lt;br /&gt;        rlock = {&lt;br /&gt;          raw_lock = {&lt;br /&gt;            slock = 0&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }, &lt;br /&gt;    truncate_count = 0, &lt;br /&gt;    nrpages = 4, &lt;br /&gt;    writeback_index = 0, &lt;br /&gt;    a_ops = 0xc125f494, &lt;br /&gt;    flags = 131290, &lt;br /&gt;    backing_dev_info = 0xc79a00b8, &lt;br /&gt;    private_lock = {&lt;br /&gt;      {&lt;br /&gt;        rlock = {&lt;br /&gt;          raw_lock = {&lt;br /&gt;            slock = 0&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }, &lt;br /&gt;    private_list = {&lt;br /&gt;      next = 0xc7474190, &lt;br /&gt;      prev = 0xc7474190&lt;br /&gt;    }, &lt;br /&gt;    assoc_mapping = 0x0&lt;br /&gt;  }, &lt;br /&gt;  i_devices = {&lt;br /&gt;    next = 0xc747419c, &lt;br /&gt;    prev = 0xc747419c&lt;br /&gt;  }, &lt;br /&gt;  {&lt;br /&gt;    i_pipe = 0x0, &lt;br /&gt;    i_bdev = 0x0, &lt;br /&gt;    i_cdev = 0x0&lt;br /&gt;  }, &lt;br /&gt;  i_generation = 1002704581, &lt;br /&gt;  i_fsnotify_mask = 0, &lt;br /&gt;  i_fsnotify_mark_entries = {&lt;br /&gt;    first = 0x0&lt;br /&gt;  }, &lt;br /&gt;  inotify_watches = {&lt;br /&gt;    next = 0xc74741b4, &lt;br /&gt;    prev = 0xc74741b4&lt;br /&gt;  }, &lt;br /&gt;  inotify_mutex = {&lt;br /&gt;    count = {&lt;br /&gt;      counter = 1&lt;br /&gt;    }, &lt;br /&gt;    wait_lock = {&lt;br /&gt;      {&lt;br /&gt;        rlock = {&lt;br /&gt;          raw_lock = {&lt;br /&gt;            slock = 0&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }, &lt;br /&gt;    wait_list = {&lt;br /&gt;      next = 0xc74741c4, &lt;br /&gt;      prev = 0xc74741c4&lt;br /&gt;    }, &lt;br /&gt;    owner = 0x0&lt;br /&gt;  }, &lt;br /&gt;  i_state = 0, &lt;br /&gt;  dirtied_when = 0, &lt;br /&gt;  i_flags = 0, &lt;br /&gt;  i_writecount = {&lt;br /&gt;    counter = -1&lt;br /&gt;  }, &lt;br /&gt;  i_security = 0x0, &lt;br /&gt;  i_acl = 0xffffffff, &lt;br /&gt;  i_default_acl = 0xffffffff, &lt;br /&gt;  i_private = 0x0&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;To identify the inode, take note on i_ino = 186584.&lt;br /&gt;&lt;br /&gt;To verify that the inode is indeed /bin/grep, i resume the execution.&lt;br /&gt;Then in the target machine's bash shell:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;root@(none)/# find /bin -inum 186584&lt;br /&gt;/bin/grep&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Ok, admittedly this post doesn't really explore much, just for the fun of it.&lt;br /&gt;If I have time to trace till the waiting (sleeping) process, then it would be more fun.&lt;br /&gt;Let see how it goes. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-6274371274572719343?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-06T20:40:20.271+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>page fault and block device, part 2</title><link>http://weichong78.blogspot.com/2010/04/page-fault-and-block-device-part-2.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Sun, 04 Apr 2010 05:08:45 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-6224097181306852274</guid><description>On the waking up mechanism upon completion.&lt;br /&gt;&lt;br /&gt;Since the page faults need block device access, the waiting thread is naturally put to sleep.&lt;br /&gt;This was done in mpage_bio_submit() via bio-&gt;bi_end_io = mpage_end_io_read.&lt;br /&gt;&lt;br /&gt;Upon completion, the wake up process is done via...&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/fs/mpage.c:&lt;br /&gt;static void mpage_end_io_read(struct bio *bio, int err)&lt;br /&gt;{&lt;br /&gt;                unlock_page(page);&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/mm/filemap.c:&lt;br /&gt;void unlock_page(struct page *page)&lt;br /&gt;{&lt;br /&gt;        wake_up_page(page, PG_locked);&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;static inline void wake_up_page(struct page *page, int bit)&lt;br /&gt;{&lt;br /&gt;    __wake_up_bit(page_waitqueue(page), &amp;page-&gt;flags, bit);&lt;br /&gt;} &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/kernel/wait.c:&lt;br /&gt;void __wake_up_bit(wait_queue_head_t *wq, void *word, int bit)&lt;br /&gt;{&lt;br /&gt;        struct wait_bit_key key = __WAIT_BIT_KEY_INITIALIZER(word, bit);&lt;br /&gt;        if (waitqueue_active(wq))&lt;br /&gt;                __wake_up(wq, TASK_NORMAL, 1, &amp;key);&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-6224097181306852274?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-04T20:08:45.297+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>page fault and block device</title><link>http://weichong78.blogspot.com/2010/04/page-fault-and-block-device.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Sat, 03 Apr 2010 19:44:03 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-4342471726830731036</guid><description>Since college days, I was always told about the theory of how a page fault would eventually lead to data being page in from the secondary storage or block device.&lt;br /&gt;In practice, this simple theory seems to be more then just a little complicated.&lt;br /&gt;Having some free time, I try to blindly browse/grep for the related code.&lt;br /&gt;I am not sure if this is one of the actual/correct path of execution when a page fault occur, leading up to the block device access to locate the data.  I am pretty sure, however, that this is definitely not the only path of execution, since there are multiple condition where page fault can happen.&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/mm/memory.c:&lt;br /&gt;&lt;br /&gt;int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,&lt;br /&gt;                unsigned long address, unsigned int flags)&lt;br /&gt;{&lt;br /&gt;        return handle_pte_fault(mm, vma, address, pte, pmd, flags);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static inline int handle_pte_fault(struct mm_struct *mm,&lt;br /&gt;                struct vm_area_struct *vma, unsigned long address,&lt;br /&gt;                pte_t *pte, pmd_t *pmd, unsigned int flags)&lt;br /&gt;{&lt;br /&gt;                                        return do_linear_fault(mm, vma, address,&lt;br /&gt;                                                pte, pmd, flags, entry);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static int do_linear_fault(struct mm_struct *mm, struct vm_area_struct *vma,&lt;br /&gt;                unsigned long address, pte_t *page_table, pmd_t *pmd,&lt;br /&gt;                unsigned int flags, pte_t orig_pte)&lt;br /&gt;{&lt;br /&gt;        return __do_fault(mm, vma, address, pmd, pgoff, flags, orig_pte);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,&lt;br /&gt;                unsigned long address, pmd_t *pmd,&lt;br /&gt;                pgoff_t pgoff, unsigned int flags, pte_t orig_pte)&lt;br /&gt;{&lt;br /&gt;        ret = vma-&gt;vm_ops-&gt;fault(vma, &amp;vmf);&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/mm/filemap.c:&lt;br /&gt;&lt;br /&gt;const struct vm_operations_struct generic_file_vm_ops = {&lt;br /&gt;        .fault          = filemap_fault,&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)&lt;br /&gt;{&lt;br /&gt;        error = mapping-&gt;a_ops-&gt;readpage(file, page);&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/fs/ext2/inode.c&lt;br /&gt;&lt;br /&gt;const struct address_space_operations ext2_aops = {&lt;br /&gt;        .readpage               = ext2_readpage,&lt;br /&gt;        .readpages              = ext2_readpages,&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static int ext2_readpage(struct file *file, struct page *page)&lt;br /&gt;{       &lt;br /&gt;        return mpage_readpage(page, ext2_get_block);&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/fs/mpage.c:&lt;br /&gt;&lt;br /&gt;int mpage_readpage(struct page *page, get_block_t get_block)&lt;br /&gt;{&lt;br /&gt;                mpage_bio_submit(READ, bio);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static struct bio *mpage_bio_submit(int rw, struct bio *bio)&lt;br /&gt;{&lt;br /&gt;        bio-&gt;bi_end_io = mpage_end_io_read;&lt;br /&gt;        if (rw == WRITE)&lt;br /&gt;                bio-&gt;bi_end_io = mpage_end_io_write;&lt;br /&gt;        submit_bio(rw, bio);&lt;br /&gt;        return NULL;&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/block/blk-core.c:&lt;br /&gt;&lt;br /&gt;void submit_bio(int rw, struct bio *bio)&lt;br /&gt;{&lt;br /&gt;        generic_make_request(bio);&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;This will just be the beginning of my investigation.  More will come.  Any guidance and feedback is welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-4342471726830731036?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-04T10:44:03.152+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>i915 mode setting code</title><link>http://weichong78.blogspot.com/2010/02/i915-mode-setting-code.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Sat, 06 Feb 2010 21:56:06 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-8363004257696569001</guid><description>In one of my previous &lt;a href="http://weichong78.blogspot.com/2009/09/playing-with-integrated-graphics-device.html"&gt;post&lt;/a&gt;, I blindly rely on the higher level code to turn the display on and off.&lt;br /&gt;Recently, I'm interested to look deeper into the i915 driver to understand how some of the mode setting code works, as explained in the good &lt;a href="http://intellinuxgraphics.org/documentation.html"&gt;Intel® 965 Express Chipset Family and Intel® G35 Express Chipset Graphics Controller PRM Programmer’s Reference Manual (PRM) Volume 3: Display Registers&lt;br /&gt;&lt;/a&gt; in www.intellinuxgraphics.org.&lt;br /&gt;&lt;br /&gt;I start my journey with linux/drivers/gpu/drm/i915/intel_display.c.&lt;br /&gt;&lt;br /&gt;First of all, I see:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux/drivers/gpu/drm/i915/intel_display.c:&lt;br /&gt;&lt;br /&gt;static const struct drm_crtc_helper_funcs intel_helper_funcs = {&lt;br /&gt;        .dpms = intel_crtc_dpms,&lt;br /&gt;        .mode_fixup = intel_crtc_mode_fixup,&lt;br /&gt;        .mode_set = intel_crtc_mode_set,&lt;br /&gt;        .mode_set_base = intel_pipe_set_base,&lt;br /&gt;        .prepare = intel_crtc_prepare,&lt;br /&gt;        .commit = intel_crtc_commit,&lt;br /&gt;        .load_lut = intel_crtc_load_lut,&lt;br /&gt;};&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;At a first glance, intel_crtc_mode_set() looks like a promising place to look for mode setting code. However, since it is register as a hook of drm_crtc_helper_funcs, I presume some high level code must be calling it.  To understand more about the calling sequence, I decided to look for the caller first.&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux/drivers/gpu/drm/drm_crtc_helper.c:&lt;br /&gt;&lt;br /&gt;bool drm_crtc_helper_set_mode(...)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;        crtc_funcs-&gt;prepare(crtc);&lt;br /&gt;&lt;br /&gt;        /* Set up the DPLL and any encoders state that needs to adjust or depend&lt;br /&gt;         * on the DPLL.&lt;br /&gt;         */&lt;br /&gt;        ret = !crtc_funcs-&gt;mode_set(crtc, mode, adjusted_mode, x, y, old_fb);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So, it is apparent that the caller will perform some preparation with intel_crtc_prepare() before calling intel_crtc_mode_set().&lt;br /&gt;&lt;br /&gt;Some of the mode switching sequence is actually documented in the PRM's section 2.2.2 Mode Switch Programming Sequences.&lt;br /&gt;&lt;br /&gt;When we look at intel_crtc_prepare(), looks like it is using some DPMS related code to turn of the display before setting the mode.&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux/drivers/gpu/drm/i915/intel_display.c:&lt;br /&gt;&lt;br /&gt;static void intel_crtc_prepare (struct drm_crtc *crtc)&lt;br /&gt;{&lt;br /&gt;        struct drm_crtc_helper_funcs *crtc_funcs = crtc-&gt;helper_private;&lt;br /&gt;        crtc_funcs-&gt;dpms(crtc, DRM_MODE_DPMS_OFF);&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;But crtc_funcs-&gt;dpms() is actually intel_crtc_dpms().&lt;br /&gt;So,&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux/drivers/gpu/drm/i915/intel_display.c:&lt;br /&gt;&lt;br /&gt;static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;        struct drm_i915_private *dev_priv = dev-&gt;dev_private;&lt;br /&gt;    ...&lt;br /&gt;        dev_priv-&gt;display.dpms(crtc, mode);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;where...&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux/drivers/gpu/drm/i915/i915_drv.h:&lt;br /&gt;&lt;br /&gt;typedef struct drm_i915_private {&lt;br /&gt;    ...&lt;br /&gt;        /* Display functions */&lt;br /&gt;        struct drm_i915_display_funcs display;&lt;br /&gt;    ...&lt;br /&gt;} drm_i915_private_t;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Note that this hook is initialized in:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux/drivers/gpu/drm/i915/intel_display.c:&lt;br /&gt;&lt;br /&gt;static void intel_init_display(struct drm_device *dev)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;        /* We always want a DPMS function */&lt;br /&gt;        if (IS_IRONLAKE(dev))&lt;br /&gt;                dev_priv-&gt;display.dpms = ironlake_crtc_dpms;&lt;br /&gt;        else&lt;br /&gt;                dev_priv-&gt;display.dpms = i9xx_crtc_dpms;&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So, in other words, intel_crtc_dpms() indirectly calls either ironlake_crtc_dpms() or i9xx_crtc_dpms(), to disable the display pipeline, depending on the GMCH type.  For this discussion, lets take i9xx_crtc_dpms() as example.&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux/drivers/gpu/drm/i915/intel_display.c:&lt;br /&gt;&lt;br /&gt;static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;        int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;&lt;br /&gt;        int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;&lt;br /&gt;        int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;&lt;br /&gt;        int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;&lt;br /&gt;    ...&lt;br /&gt;        case DRM_MODE_DPMS_OFF:&lt;br /&gt;    ...&lt;br /&gt;                /* Disable display plane */&lt;br /&gt;                temp = I915_READ(dspcntr_reg);&lt;br /&gt;                if ((temp &amp; DISPLAY_PLANE_ENABLE) != 0) {&lt;br /&gt;                        I915_WRITE(dspcntr_reg, temp &amp; ~DISPLAY_PLANE_ENABLE);&lt;br /&gt;                        /* Flush the plane changes */&lt;br /&gt;                        I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));&lt;br /&gt;                        I915_READ(dspbase_reg);&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                if (!IS_I9XX(dev)) {&lt;br /&gt;                        /* Wait for vblank for the disable to take effect */&lt;br /&gt;                        intel_wait_for_vblank(dev);&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                /* Next, disable display pipes */&lt;br /&gt;                temp = I915_READ(pipeconf_reg);&lt;br /&gt;                if ((temp &amp; PIPEACONF_ENABLE) != 0) {&lt;br /&gt;                        I915_WRITE(pipeconf_reg, temp &amp; ~PIPEACONF_ENABLE);&lt;br /&gt;                        I915_READ(pipeconf_reg);&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                /* Wait for vblank for the disable to take effect. */&lt;br /&gt;                intel_wait_for_vblank(dev);&lt;br /&gt;&lt;br /&gt;                temp = I915_READ(dpll_reg);&lt;br /&gt;                if ((temp &amp; DPLL_VCO_ENABLE) != 0) {&lt;br /&gt;                        I915_WRITE(dpll_reg, temp &amp; ~DPLL_VCO_ENABLE);&lt;br /&gt;                        I915_READ(dpll_reg);&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                /* Wait for the clocks to turn off. */&lt;br /&gt;                udelay(150);&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The mode switching disabling sequence is explained in the PRM as follow:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;2.2.2 Mode Switch Programming Sequences&lt;br /&gt;    ...&lt;br /&gt;    • Planes must be disabled before pipe is disabled or pipe timings changed.&lt;br /&gt;    ...&lt;br /&gt;    Table 2-1. Mode Switch Sequences&lt;br /&gt;    ...&lt;br /&gt;                                       Disable sequence&lt;br /&gt;    ...&lt;br /&gt;    Disable ports&lt;br /&gt;    Disable planes (VGA or hires)&lt;br /&gt;    Disable pipe&lt;br /&gt;    Disable VGA display in 0x71400 bit 31&lt;br /&gt;    (Disable VGA display done after disable pipe to allow pipe to turn off when no vblank is available in native VGA mode)&lt;br /&gt;    If Gen4 { Wait for pipe off status }&lt;br /&gt;    (Wait ensures planes and pipe have completely turned off prior to disabling panelfitter then&lt;br /&gt;DPLL)&lt;br /&gt;    Disable panelfitter&lt;br /&gt;    Disable DPLL&lt;br /&gt;    ...&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;After the disabling sequence comes the enabling sequence, where drm_crtc_helper_set_mode() will indirectly call intel_crtc_mode_set() via the crtc_funcs hooks.&lt;br /&gt;&lt;br /&gt;Firstly, the reference clock frequency is determined.&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux/drivers/gpu/drm/i915/intel_display.c:&lt;br /&gt;&lt;br /&gt;static int intel_crtc_mode_set(...)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;        } else if (IS_I9XX(dev)) {&lt;br /&gt;                refclk = 96000;&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The information about reference clock can be seen in the PRM:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;2.5 Display Clock Control Registers (06000h–06FFFh)&lt;br /&gt;&lt;br /&gt;Reference Frequency: &lt;br /&gt;96MHz for SDVO CRT, HDMI,&lt;br /&gt;96MHz or 100MHz for LVDS.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;After performing some DPLL magic (magic because my shallow knowledge doesn't fully comprehend the PRM yet :-), intel_crtc_set_mode() proceed to set the new "mode":&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux/drivers/gpu/drm/i915/intel_display.c:&lt;br /&gt;&lt;br /&gt;static int intel_crtc_mode_set(...)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;        /* setup pipeconf */&lt;br /&gt;        pipeconf = I915_READ(pipeconf_reg);&lt;br /&gt;&lt;br /&gt;        /* Set up the display plane register */&lt;br /&gt;        dspcntr = DISPPLANE_GAMMA_ENABLE;&lt;br /&gt;    ...&lt;br /&gt;        dspcntr |= DISPLAY_PLANE_ENABLE;&lt;br /&gt;        pipeconf |= PIPEACONF_ENABLE;&lt;br /&gt;        dpll |= DPLL_VCO_ENABLE;&lt;br /&gt;    ...&lt;br /&gt;        I915_WRITE(htot_reg, (adjusted_mode-&gt;crtc_hdisplay - 1) |&lt;br /&gt;                   ((adjusted_mode-&gt;crtc_htotal - 1) &lt;&lt; 16));&lt;br /&gt;        I915_WRITE(hblank_reg, (adjusted_mode-&gt;crtc_hblank_start - 1) |&lt;br /&gt;                   ((adjusted_mode-&gt;crtc_hblank_end - 1) &lt;&lt; 16));&lt;br /&gt;        I915_WRITE(hsync_reg, (adjusted_mode-&gt;crtc_hsync_start - 1) |&lt;br /&gt;                   ((adjusted_mode-&gt;crtc_hsync_end - 1) &lt;&lt; 16));&lt;br /&gt;        I915_WRITE(vtot_reg, (adjusted_mode-&gt;crtc_vdisplay - 1) |&lt;br /&gt;                   ((adjusted_mode-&gt;crtc_vtotal - 1) &lt;&lt; 16));&lt;br /&gt;        I915_WRITE(vblank_reg, (adjusted_mode-&gt;crtc_vblank_start - 1) |&lt;br /&gt;                   ((adjusted_mode-&gt;crtc_vblank_end - 1) &lt;&lt; 16));&lt;br /&gt;        I915_WRITE(vsync_reg, (adjusted_mode-&gt;crtc_vsync_start - 1) |&lt;br /&gt;                   ((adjusted_mode-&gt;crtc_vsync_end - 1) &lt;&lt; 16));&lt;br /&gt;    ...&lt;br /&gt;        I915_WRITE(pipesrc_reg, ((mode-&gt;hdisplay - 1) &lt;&lt; 16) | (mode-&gt;vdisplay - 1));&lt;br /&gt;    ...&lt;br /&gt;        I915_WRITE(pipeconf_reg, pipeconf);&lt;br /&gt;        I915_READ(pipeconf_reg);&lt;br /&gt;&lt;br /&gt;        intel_wait_for_vblank(dev);&lt;br /&gt;    ...&lt;br /&gt;        I915_WRITE(dspcntr_reg, dspcntr);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Much of the information about mode adjustment code can be found in the PRM section 2.7 Display Pipeline / Port Registers (60000h–6FFFFh), 2.10.1.3 PIPEACONF—Pipe A Configuration Register and also Enable sequence in 2.2.2 Mode Switch Programming Sequences.&lt;br /&gt;&lt;br /&gt;I guess that is the overall flow of what happen during a KMS mode setting like when we use xrandr to select another resolution.&lt;br /&gt;Having said that, this is just the beginning of my investigation and nothing here is authoritative.  If any of you understand better, please do enlighten me.  Any advise is welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-8363004257696569001?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-07T13:56:06.864+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>OpenOffice Automation with Python</title><link>http://weichong78.blogspot.com/2010/02/openoffice-automation-with-python.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Thu, 04 Feb 2010 04:41:18 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-8318841942197484124</guid><description>Linux and UNIX users tend to automate many things with script and I'm no exception.&lt;br /&gt;However, most of the scripting skill I have learned tend to deal with text files and text terminal.&lt;br /&gt;Lately, I am interested to learn how to apply similar scripting automation to modern GUI application after noticing a few of my friends have trouble with spreadsheet formula verifications.&lt;br /&gt;&lt;br /&gt;After browsing around the web and some useful advice from friend forum users, I started to out to try some ad hoc script on OpenOffice.org 3.1 using Python.&lt;br /&gt;&lt;br /&gt;Here is my ad hoc script that populate two simple column with data and generate a chart from there:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;from com.sun.star.awt import Rectangle&lt;br /&gt;&lt;br /&gt;def populateSheet1():&lt;br /&gt; ctx = XSCRIPTCONTEXT.getComponentContext()&lt;br /&gt; doc = XSCRIPTCONTEXT.getDocument()&lt;br /&gt; shs = doc.getSheets()&lt;br /&gt; sht = shs.getByName("Sheet1")&lt;br /&gt; crg = sht.getCellRangeByName("A1:B1")&lt;br /&gt; crg.setPropertyValue("CellBackColor", 0xF000F0)&lt;br /&gt; cel = sht.getCellByPosition(0,0)&lt;br /&gt; cel.setFormula("value")&lt;br /&gt; sht.getCellByPosition(1,0).setFormula("value x 2")&lt;br /&gt; crg = sht.getCellRangeByName("A2:A11")&lt;br /&gt; crg.setPropertyValue("CellBackColor", 0x00F0F0)&lt;br /&gt; for r in range(1,11):&lt;br /&gt;  cel = sht.getCellByPosition(0,r)&lt;br /&gt;  cel.setValue(r)&lt;br /&gt;  cel = sht.getCellByPosition(1,r)&lt;br /&gt;  fml = "=A" + str(r+1) + "*2"&lt;br /&gt;  cel.setFormula(fml)&lt;br /&gt; adr = sht.getCellRangeByName("A2:A11").getRangeAddress()&lt;br /&gt; a = (adr,)&lt;br /&gt; # Properties can be access directly or using getPropertyValue()&lt;br /&gt; siz = sht.getCellByPosition(2,0).Size&lt;br /&gt; pos = sht.getCellByPosition(2,0).getPropertyValue("Position")&lt;br /&gt; rect = Rectangle()&lt;br /&gt; rect.X = pos.X&lt;br /&gt; rect.Y = pos.Y&lt;br /&gt; rect.Width = siz.Width * 3&lt;br /&gt; rect.Height = siz.Height * 11&lt;br /&gt; chs = sht.getCharts()&lt;br /&gt; chs.addNewByName("Chart1", rect, a, True, False)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The result is...&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_dI98ThVL4ak/S2rANXSKn_I/AAAAAAAAAf4/TucIT3c5X5g/s1600-h/ooo_python1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 92px;" src="http://4.bp.blogspot.com/_dI98ThVL4ak/S2rANXSKn_I/AAAAAAAAAf4/TucIT3c5X5g/s200/ooo_python1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5434367236196966386" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-8318841942197484124?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-04T20:41:18.847+08:00</app:edited><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_dI98ThVL4ak/S2rANXSKn_I/AAAAAAAAAf4/TucIT3c5X5g/s72-c/ooo_python1.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Linux ACPI processor and C-states</title><link>http://weichong78.blogspot.com/2010/01/linux-acpi-processor-and-c-states.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Wed, 13 Jan 2010 07:43:04 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-3417345202960367671</guid><description>I always wanted to understand how Linux ACPI subsystem prepare my laptop CPU for entering C-state when it has nothing productive to do.&lt;br /&gt;After some kernel code reading, below is what I believe how it works.&lt;br /&gt;&lt;br /&gt;Firstly, the ACPI code scan the system and register anything it can find.&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;drivers/acpi/scan.c&lt;br /&gt;:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;struct bus_type acpi_bus_type = {&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    .probe = acpi_device_probe,&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static int acpi_device_probe(struct device * dev)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    ret = acpi_bus_driver_init(acpi_dev, acpi_drv);&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static int acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    result = driver-&gt;ops.add(device);&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Particularly, ACPI code will add the device and driver for ACPI processor.&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;drivers/acpi/processor_core.c:&lt;br /&gt;&lt;br /&gt;static struct acpi_driver acpi_processor_driver = {&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    .add = acpi_processor_add,&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static int __cpuinit acpi_processor_add(struct acpi_device *device)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    acpi_processor_power_init(pr, device);&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;When a processor is found or "added", it obtains the relevant information in this way.&lt;br /&gt;acpi_processor_get_power_info_cst() is where the bulk of the initialization is done, &lt;br /&gt;especially on &lt;br /&gt;struct acpi_processor_cx.&lt;br /&gt;Here it reads the ACPI _CST object from BIOS.&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;drivers/acpi/processor_idle.c:&lt;br /&gt;&lt;br /&gt;int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    acpi_processor_get_power_info(pr);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static int acpi_processor_get_power_info(struct acpi_processor *pr)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    result = acpi_processor_get_power_info_cst(pr);&lt;br /&gt;&lt;br /&gt;    if (result == -ENODEV)&lt;br /&gt;&lt;br /&gt;        result = acpi_processor_get_power_info_fadt(pr);&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    status = acpi_evaluate_object(pr-&gt;handle, "_CST", NULL, &amp;buffer);&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    if (reg-&gt;space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {&lt;br /&gt;&lt;br /&gt;        if (acpi_processor_ffh_cstate_probe(pr-&gt;id, &amp;cx, reg) == 0) {&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Finally, the architecture specific code will fill in the details:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;arch/x86/kernel/acpi/cstate.c:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#define MWAIT_ECX_INTERRUPT_BREAK       (0x1)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;int acpi_processor_ffh_cstate_probe(unsigned int cpu, struct acpi_processor_cx *cx, struct acpi_power_register *reg)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    retval = work_on_cpu(cpu, acpi_processor_ffh_cstate_probe_cpu, cx);&lt;br /&gt;&lt;br /&gt;    if (retval == 0) {&lt;br /&gt;&lt;br /&gt;        /* Use the hint in CST */&lt;br /&gt;&lt;br /&gt;        percpu_entry-&gt;states[cx-&gt;index].eax = cx-&gt;address;&lt;br /&gt;&lt;br /&gt;        percpu_entry-&gt;states[cx-&gt;index].ecx = MWAIT_ECX_INTERRUPT_BREAK;&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static long acpi_processor_ffh_cstate_probe_cpu(void *_cx)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    cpuid(CPUID_MWAIT_LEAF, &amp;eax, &amp;ebx, &amp;ecx, &amp;edx);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /* Check whether this particular cx_type (in CST) is supported or not */&lt;br /&gt;&lt;br /&gt;    cstate_type = ((cx-&gt;address &gt;&gt; MWAIT_SUBSTATE_SIZE) &amp;  MWAIT_CSTATE_MASK) + 1;&lt;br /&gt;&lt;br /&gt;    edx_part = edx &gt;&gt; (cstate_type * MWAIT_SUBSTATE_SIZE);&lt;br /&gt;&lt;br /&gt;    num_cstate_subtype = edx_part &amp; MWAIT_SUBSTATE_MASK;&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;How does the kernel actually make the CPU enter C-state? It usually trigger it via the cpuidle subsystem code, which we will discuss on another day :).  But just the ACPI processor portion, here is a preview:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    mwait_idle_with_hints(percpu_entry-&gt;states[cx-&gt;index].eax,&lt;br /&gt;&lt;br /&gt;                          percpu_entry-&gt;states[cx-&gt;index].ecx);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-3417345202960367671?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-13T23:43:04.967+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Linux ACPI T-state Processor Throttling, Part 1</title><link>http://weichong78.blogspot.com/2010/01/linux-acpi-t-state-processor-throttling.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Thu, 07 Jan 2010 06:31:33 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-4472832805252759352</guid><description>Lately, T-state caught my attention.&lt;br /&gt;So, let's start browsing over some kernel code.&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/drivers/acpi/processor_core.c:&lt;br /&gt;&lt;br /&gt;static int __init acpi_processor_init(void)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    result = acpi_bus_register_driver(&amp;acpi_processor_driver);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;where&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/drivers/acpi/processor_core.c:&lt;br /&gt;&lt;br /&gt;static struct acpi_driver acpi_processor_driver = {&lt;br /&gt;        .name = "processor",&lt;br /&gt;        .class = ACPI_PROCESSOR_CLASS,&lt;br /&gt;        .ids = processor_device_ids,&lt;br /&gt;        .ops = {&lt;br /&gt;                .add = acpi_processor_add,&lt;br /&gt;                .remove = acpi_processor_remove,&lt;br /&gt;                .suspend = acpi_processor_suspend,&lt;br /&gt;                .resume = acpi_processor_resume,&lt;br /&gt;                .notify = acpi_processor_notify,&lt;br /&gt;                },&lt;br /&gt;};&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So, from the look of it, upon detection of a newly "added" processor, I guess...&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/drivers/acpi/processor_core.c:&lt;br /&gt;&lt;br /&gt;static int __cpuinit acpi_processor_add(struct acpi_device *device)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    acpi_processor_get_throttling_info(pr);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int acpi_processor_get_throttling_info(struct acpi_processor *pr)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;        /*&lt;br /&gt;         * Evaluate _PTC, _TSS and _TPC&lt;br /&gt;         * They must all be present or none of them can be used.&lt;br /&gt;         */&lt;br /&gt;        if (acpi_processor_get_throttling_control(pr) ||&lt;br /&gt;                acpi_processor_get_throttling_states(pr) ||&lt;br /&gt;                acpi_processor_get_platform_limit(pr))&lt;br /&gt;        {&lt;br /&gt;                pr-&gt;throttling.acpi_processor_get_throttling =&lt;br /&gt;                    &amp;acpi_processor_get_throttling_fadt;&lt;br /&gt;                pr-&gt;throttling.acpi_processor_set_throttling =&lt;br /&gt;                    &amp;acpi_processor_set_throttling_fadt;&lt;br /&gt;                if (acpi_processor_get_fadt_info(pr))&lt;br /&gt;                        return 0;&lt;br /&gt;        } else {&lt;br /&gt;    ...&lt;br /&gt;        if (acpi_processor_get_tsd(pr)) {&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;browsing along...&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/drivers/acpi/processor_throttling.c:&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * _PTC - Processor Throttling Control (and status) register location&lt;br /&gt; */&lt;br /&gt;static int acpi_processor_get_throttling_control(struct acpi_processor *pr)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    status = acpi_evaluate_object(pr-&gt;handle, "_PTC", NULL, &amp;buffer);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;where according to ACPI 3.0a spec:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;8.4.3.1 _PTC (Processor Throttling Control)&lt;br /&gt;_PTC is an optional object that defines a processor throttling control interface alternative to the I/O address spaced-based P_BLK throttling control register (P_CNT)&lt;br /&gt;...&lt;br /&gt;OSPM performs processor throttling control by writing the Control field value for the target throttling state (T-state), retrieved from the Throttling Supported States object (_TSS), to the Throttling Control Register (THROTTLE_CTRL) defined by the _PTC object. &lt;br /&gt;...&lt;br /&gt;The _PTC object contains data in the following format:&lt;br /&gt;Name (_PTC, Package()&lt;br /&gt;{&lt;br /&gt;    ResourceTemplate(){Throttling_Control_Register},       //Generic Register Descriptor&lt;br /&gt;    ResourceTemplate(){Throttling_Status_Register}     //Generic Register Descriptor&lt;br /&gt;}) // End of _PTC&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So, back to the code:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;/*&lt;br /&gt; * _TSS - Throttling Supported States&lt;br /&gt; */&lt;br /&gt;static int acpi_processor_get_throttling_states(struct acpi_processor *pr)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    status = acpi_evaluate_object(pr-&gt;handle, "_TSS", NULL, &amp;buffer);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;where according to ACPI 3.0a spec:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;8.4.3.2 _TSS (Throttling Supported States)&lt;br /&gt;This optional object indicates to OSPM the number of supported processor throttling states that a platform supports.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Again, back to the code:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/drivers/acpi/processor_throttling.c:&lt;br /&gt;&lt;br /&gt;/*                        &lt;br /&gt; * _TPC - Throttling Present Capabilities&lt;br /&gt; */                       &lt;br /&gt;static int acpi_processor_get_platform_limit(struct acpi_processor *pr)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    status = acpi_evaluate_integer(pr-&gt;handle, "_TPC", NULL, &amp;tpc);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;where the ACPI 3.0a spec says:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;8.4.3.3 _TPC (Throttling Present Capabilities)&lt;br /&gt;This optional object is a method that dynamically indicates to OSPM the number of throttling states currently supported by the platform. This method returns a number that indicates the _TSS entry number of the highest power throttling state that OSPM can use at a given time. OSPM may choose the corresponding state entry in the _TSS as indicated by the value returned by the _TPC method or any lower power (higher numbered) state entry in the _TSS.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Looking acpi_processor_get_tsd():&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux-2.6/drivers/acpi/processor_throttling.c:&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * _TSD - T-State Dependencies&lt;br /&gt; */&lt;br /&gt;static int acpi_processor_get_tsd(struct acpi_processor *pr)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    status = acpi_evaluate_object(pr-&gt;handle, "_TSD", NULL, &amp;buffer);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;where again, according to the ACPI 3.0a spec:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;8.4.3.4 _TSD (T-State Dependency)&lt;br /&gt;This optional object provides T-state control cross logical processor dependency information to OSPM.&lt;br /&gt;The _TSD object evaluates to a packaged list of information that correlates with the T-state information returned by the _TSS object. Each packaged list entry identifies a dependency domain number for the logical processor’s T-states, the coordination type for that T-state and the number of logical processors belonging to the domain.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Ok, thats all for a quick 15 minutes investigation for tonight.  More to be continue in future post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-4472832805252759352?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-07T22:31:33.153+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>CPU Temperature via lm-sensors vs ACPI</title><link>http://weichong78.blogspot.com/2010/01/cpu-temperature-via-lm-sensors-vs-acpi.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Sun, 03 Jan 2010 19:17:58 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-7019967319135016906</guid><description>Recently, I'm curious about how Linux detect/report my laptop health, particularly the CPU temperature and learn that there are actually at least 2 related but not identical way of obtaining such information.  One via ACPI and another via lm-sensors infrastructure.&lt;br /&gt;&lt;br /&gt;For lm-sensors running on my personal laptop, it can utilize the coretemp driver which basically just read of the IA32_THERM_STATUS MSR (0x19C), as can be seen from the kernel code below:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux/drivers/hwmon/coretemp.c:&lt;br /&gt;&lt;br /&gt;static struct coretemp_data *coretemp_update_device(struct device *dev)&lt;br /&gt;{&lt;br /&gt;    struct coretemp_data *data = dev_get_drvdata(dev);&lt;br /&gt;    ...&lt;br /&gt;        rdmsr_on_cpu(data-&gt;id, MSR_IA32_THERM_STATUS, &amp;eax, &amp;edx);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;For ACPI related code, my guess is that the kernel depends on ACPI _TMP Object in obtaining the temperature of the "thermal zone", as can be seen from the snippet below:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;linux/drivers/acpi/thermal.c:&lt;br /&gt;&lt;br /&gt;static int acpi_thermal_get_info(struct acpi_thermal *tz)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    /* Get temperature [_TMP] (required) */&lt;br /&gt;    result = acpi_thermal_get_temperature(tz);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static int acpi_thermal_get_temperature(struct acpi_thermal *tz)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    status = acpi_evaluate_integer(tz-&gt;device-&gt;handle, "_TMP", NULL, &amp;tmp);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;From the ACPI 3.0a spec I downloaded, it states that _TMP is the "Thermal zone object that returns current temperature in tenths of degrees Kelvin".&lt;br /&gt;So, it depends on how my laptop ACPI (BIOS) implements _TMP, that is what I get, I guess.&lt;br /&gt;In the meantime, I'm still curious about the code in linux/drivers/acpi/processor_thermal.c.  But that will be for my next post :-).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-7019967319135016906?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-04T11:17:58.148+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>cpufreq and acpi</title><link>http://weichong78.blogspot.com/2010/01/cpufreq-and-acpi.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Thu, 31 Dec 2009 17:22:29 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-6889665805598240127</guid><description>Happy New Year 2010, everybody!&lt;br /&gt;Let this be my first post in 2010 :)&lt;br /&gt;&lt;br /&gt;Ok, so lately I'm curious about how my laptop's acpi-cpufreq gets its value:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;weichong78@weichong78-ulv:/sys/devices/system/cpu/cpu0/cpufreq$ cat scaling_available_frequencies &lt;br /&gt;1300000 1200000 &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So, I dive straight into the code of arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c.&lt;br /&gt;In the initialization code:&lt;br /&gt;&lt;div classs="mycode"&gt;&lt;br /&gt;static int __init acpi_cpufreq_init(void)&lt;br /&gt;{   &lt;br /&gt;    ...&lt;br /&gt;    ret = cpufreq_register_driver(&amp;acpi_cpufreq_driver);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;where acpi_cpufreq_driver is:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;static struct cpufreq_driver acpi_cpufreq_driver = {&lt;br /&gt;        .verify         = acpi_cpufreq_verify,&lt;br /&gt;        .target         = acpi_cpufreq_target,&lt;br /&gt;        .bios_limit     = acpi_processor_get_bios_limit,&lt;br /&gt;        .init           = acpi_cpufreq_cpu_init,&lt;br /&gt;        .exit           = acpi_cpufreq_cpu_exit,&lt;br /&gt;        .resume         = acpi_cpufreq_resume,&lt;br /&gt;        .name           = "acpi-cpufreq",&lt;br /&gt;        .owner          = THIS_MODULE,&lt;br /&gt;        .attr           = acpi_cpufreq_attr,&lt;br /&gt;};&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In acpi_cpufreq_cpu_init:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    struct acpi_cpufreq_data *data;&lt;br /&gt;    ...&lt;br /&gt;    struct acpi_processor_performance *perf;&lt;br /&gt;    ...&lt;br /&gt;    result = acpi_processor_register_performance(data-&gt;acpi_data, cpu);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;We can find in drivers/acpi/processor_perflib.c:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;int&lt;br /&gt;acpi_processor_register_performance(struct acpi_processor_performance&lt;br /&gt;                                    *performance, unsigned int cpu)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    if (acpi_processor_get_performance_info(pr)) {&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static int acpi_processor_get_performance_info(struct acpi_processor *pr)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    status = acpi_get_handle(pr-&gt;handle, "_PCT", &amp;handle);&lt;br /&gt;    ...&lt;br /&gt;    result = acpi_processor_get_performance_control(pr);&lt;br /&gt;    ...&lt;br /&gt;    result = acpi_processor_get_performance_states(pr);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static int acpi_processor_get_performance_control(struct acpi_processor *pr)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    status = acpi_evaluate_object(pr-&gt;handle, "_PCT", NULL, &amp;buffer);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static int acpi_processor_get_performance_states(struct acpi_processor *pr)&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;    status = acpi_evaluate_object(pr-&gt;handle, "_PSS", NULL, &amp;buffer);&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So, there we have it, acpi-cpufreq takes from ACPI _PCT and _PSS.  But from where? And what do they mean?&lt;br /&gt;&lt;br /&gt;After some investigation, I try the below:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;weichong78@weichong78-ulv:/tmp$ cp /sys/firmware/acpi/tables/dynamic/SSDT* .&lt;br /&gt;weichong78@weichong78-ulv:/tmp$ cp /sys/firmware/acpi/tables/SSDT* .&lt;br /&gt;weichong78@weichong78-ulv:/tmp$ iasl -d SSDT*&lt;br /&gt;&lt;br /&gt;weichong78@weichong78-ulv:/tmp$ grep _PCT SSDT*&lt;br /&gt;Binary file SSDT3 matches&lt;br /&gt;SSDT3.dsl:        Method (_PCT, 0, NotSerialized)&lt;br /&gt;Binary file SSDT5 matches&lt;br /&gt;SSDT5.dsl:        Method (_PCT, 0, NotSerialized)&lt;br /&gt;SSDT5.dsl:        Method (_PCT, 0, NotSerialized)&lt;br /&gt;SSDT5.dsl:            Return (\_PR.CPU1._PCT ())&lt;br /&gt;SSDT5.dsl:        Method (_PCT, 0, NotSerialized)&lt;br /&gt;SSDT5.dsl:            Return (\_PR.CPU1._PCT ())&lt;br /&gt;&lt;br /&gt;weichong78@weichong78-ulv:/tmp$ grep _PSS SSDT*&lt;br /&gt;Binary file SSDT3 matches&lt;br /&gt;SSDT3.dsl:        Name (_PSS, Package (0x02)&lt;br /&gt;Binary file SSDT5 matches&lt;br /&gt;SSDT5.dsl:    External (\_PR_.CPU0._PSS, IntObj)&lt;br /&gt;SSDT5.dsl:        Method (_PSS, 0, NotSerialized)&lt;br /&gt;SSDT5.dsl:            Return (\_PR.CPU0._PSS)&lt;br /&gt;SSDT5.dsl:        Method (_PSS, 0, NotSerialized)&lt;br /&gt;SSDT5.dsl:            Return (\_PR.CPU1._PSS ())&lt;br /&gt;SSDT5.dsl:        Method (_PSS, 0, NotSerialized)&lt;br /&gt;SSDT5.dsl:            Return (\_PR.CPU1._PSS ())&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Ok, so _PCT and _PSS are found under SSDT.  Now, there is only one thing left to find out, the definitions of _PCT and _PSS.  The best place to find such info is of course the ACPI spec.&lt;br /&gt;Rather then writing them in my own words, I'm going to just quote from the copy of Advanced Configuration and Power Interface Specification 3.0a that I just downloaded.&lt;br /&gt;&lt;br /&gt;For _PCT:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;8.4.4.1 _PCT (Performance Control)&lt;br /&gt;This optional object declares an interface that allows OSPM to transition the processor into a performance state. OSPM performs processor performance transitions by writing the performance state–specific control value to a Performance Control Register (PERF_CTRL).&lt;br /&gt;OSPM may select a processor performance state as indicated by the performance state value returned by the _PPC method, or any lower power (higher numbered) state. The control value to write is contained in the corresponding _PSS entry’s “Control” field.&lt;br /&gt;Success or failure of the processor performance transition is determined by reading a Performance Status Register (PERF_STATUS) to determine the processor’s current performance state. If the transition was successful, the value read from PERF_STATUS will match the “Status” field in the _PSS entry that corresponds to the desired processor performance state.&lt;br /&gt;This object evaluates to a package that declares the above-mentioned transition control and status addresses&lt;br /&gt;as follows:&lt;br /&gt;Name (_PCT, Package()&lt;br /&gt;{&lt;br /&gt;     ResourceTemplate(){Perf_Ctrl_Register},&lt;br /&gt;     ResourceTemplate(){Perf_Status_Register}&lt;br /&gt;}) // End of _PCT&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;8.4.4.2 _PSS (Performance Supported States)&lt;br /&gt;This optional object indicates to OSPM the number of supported processor performance states that any given system can support. This object evaluates to a packaged list of information about available performance states including internal CPU core frequency, typical power dissipation, control register values needed to transition between performance states, and status register values that allow OSPM to verify performance transition status after any OS-initiated transition change request. The list is sorted in descending order by typical power dissipation. As a result, the zeroth entry describes the highest performance state and the ‘nth’ entry describes the lowest performance state.&lt;br /&gt;&lt;br /&gt;Name (_PSS, Package()&lt;br /&gt;{        // Field Name                              Field Type&lt;br /&gt;    Package ()                                      // Performance State 0 Definition – P0&lt;br /&gt;    {&lt;br /&gt;         CoreFreq,                                  // DWordConst&lt;br /&gt;         Power,                                     // DWordConst&lt;br /&gt;         TransitionLatency,                         // DWordConst&lt;br /&gt;         BusMasterLatency,                          // DWordConst&lt;br /&gt;         Control,                                   // DWordConst&lt;br /&gt;         Status                                     // DWordConst&lt;br /&gt;    },&lt;br /&gt;    .&lt;br /&gt;    .&lt;br /&gt;    .&lt;br /&gt;    Package ()                                      // Performance State n Definition – Pn&lt;br /&gt;    {&lt;br /&gt;         CoreFreq,                                  // DWordConst&lt;br /&gt;         Power,                                     // DWordConst&lt;br /&gt;         TransitionLatency,                         // DWordConst&lt;br /&gt;         BusMasterLatency,                          // DWordConst&lt;br /&gt;         Control,                                   // DWordConst&lt;br /&gt;         Status                                     // DWordConst&lt;br /&gt;    }&lt;br /&gt;}) // End of _PSS object&lt;br /&gt;Each performance state entry contains six data fields as follows:&lt;br /&gt;• CoreFreq. Indicates the core CPU operating frequency (in MHz).&lt;br /&gt;• Power. Indicates the performance state’s maximum power dissipation (in milliWatts).&lt;br /&gt;• TransitionLatency. Indicates the worst-case latency in microseconds that the CPU is unavailable during a transition from any performance state to this performance state.&lt;br /&gt;• BusMasterLatency. Indicates the worst-case latency in microseconds that Bus Masters are prevented from accessing memory during a transition from any performance state to this performance state.&lt;br /&gt;• Control. Indicates the value to be written to the Performance Control Register (PERF_CTRL) in order to initiate a transition to the performance state.&lt;br /&gt;• Status. Indicates the value that OSPM will compare to a value read from the Performance Status&lt;br /&gt;Register (PERF_STATUS) to ensure that the transition to the performance state was successful. OSPM may always place the CPU in the lowest power state, but additional states are only available when indicated by the _PPC method.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So, there we have it, Happy New Year! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-6889665805598240127?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-01T09:22:29.737+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>startup_32 continues...</title><link>http://weichong78.blogspot.com/2009/12/startup32-continues.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Fri, 11 Dec 2009 06:31:22 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-5232873766763140460</guid><description>One year later, I finally have the time and opportunity to continue my exploration of Linux kernel boot code, following my previous posts &lt;a href="http://weichong78.blogspot.com/2008/04/bzimage-setupbin-headers-boot-sector.html"&gt;here&lt;/a&gt;, &lt;a href="http://weichong78.blogspot.com/2008/04/bzimage-setupbin-headers-boot-sector_02.html"&gt;here&lt;/a&gt;, &lt;a href="http://weichong78.blogspot.com/2008/04/bzimage-setupbin-headers-part-3.html"&gt;here&lt;/a&gt;, &lt;a href="http://weichong78.blogspot.com/2008/08/startup32-compressed.html"&gt;here&lt;/a&gt; and &lt;a href="http://weichong78.blogspot.com/2008/08/startup32-kernel.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For Bootstrap Processor (BSP), the code start at:&lt;br /&gt;&lt;div class="mycode"&gt;startup_32 (arch/x86/kernel/head_32.S)&lt;/div&gt;&lt;br /&gt;The execution started by setting up GDT (first with boot_gdt_descr, later with early_gdt_descr) and IDT, and also copy boot_params to another location.  It also initialize page tables using swapper_pg_dir etc.  Some of these detail can be found on books, so I'm going to just skip over.&lt;br /&gt;Application Processor (AP) also executes some of these code, but it started from startup_32_smp rather then from the beginning of startup_32.&lt;br /&gt;&lt;br /&gt;Approaching the end of startup_32, it jumps to the location pointed by:&lt;br /&gt;&lt;div class="mycode"&gt;*initial_code (arch/x86/kernel/head_32.S)&lt;/div&gt;&lt;br /&gt;which is:&lt;br /&gt;&lt;div class="mycode"&gt;i386_start_kernel (arch/x86/kernel/head32.c)&lt;/div&gt;&lt;br /&gt;Here in i386_start_kernel, memory is reserved for trampoline code (which we will investigate some other day :-), and the built in kernel initramfs, which is excellently documented &lt;a href="http://www.linux.com/learn/linux-training/114923-the-kernel-newbie-corner-qinitrdq-and-qinitramfsq-some-unfinished-business"&gt;here&lt;/a&gt;.&lt;br /&gt;Then, from the x86 specific code, it jumps to the architecture independent code at:&lt;br /&gt;&lt;div class="mycode"&gt;start_kernel (init/main.c)&lt;/div&gt;&lt;br /&gt;which is explained in some of the good kernel book, such as Professional Linux Kernel Architecture by Wolfgang Mauerer.&lt;br /&gt;Among other things, start_kernel also call x86 specific code in:&lt;br /&gt;&lt;div class="mycode"&gt;setup_arch (arch/x86/kernel/setup.c)&lt;/div&gt;&lt;br /&gt;which I will be interested to inspect with more detail in the near future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-5232873766763140460?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-11T22:31:22.470+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>kernel rpmbuild shortcut</title><link>http://weichong78.blogspot.com/2009/11/kernel-rpmbuild-shortcut.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Sat, 07 Nov 2009 20:23:23 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-8589948374997732471</guid><description>Admittedly I'm more of a Debian/Ubuntu fan than a Fedora/Redhat fan.  But occasionally I need to dive into the RPM world too.&lt;br /&gt;One thing that troubles me (maybe it is due to my shallow understanding) is kernel compilation in the RPM world.&lt;br /&gt;I know 2 different proper ways of kernel compilation in the RPM land:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;1. Using the git kernel, we can do a 'make rpm-pkg'.&lt;br /&gt;2. Using the src.rpm, we can do a rpmbuild -bb.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;However, neither of these method fits my need.  To be more specific, I need a method which, after my first complete compilation, allows me to just do minor modification, compile only that portion and link everything again.  This is important to me when I need to do random ad hoc changes and don't wish to wait for a complete rebuild, since the kernel is only for my own personal experimental usage, and not a production build.&lt;br /&gt;Using method 1, for it seems that unlike 'make deb-pkg', 'make rpm-pkg' seems to 'rm -rf' the entire build tree and rebuild the entire kernel again from scratch each time it is run.  While method 2 let me short cut the build using command like 'rpmbuild -bi' etc, it won't let me complete the build (or maybe I just don't know the right way).&lt;br /&gt;So, usually what I do is 'make deb-pkg' in a .DEB world, and then use 'alien -r' to switch it to RPM.  While handy, this method would not work in a real .RPM distro.&lt;br /&gt;Lately, however, I have discover a new workaround by observing how 'alien -r -v' works.&lt;br /&gt;Below, I will describe the method I use with a git kernel, .src.rpm kernel can be similarly used by unpacking the kernel source.&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;1. In linux/ source tree, perform a 1st round of complete kernel build using the vanilla 'make' command.&lt;br /&gt;2. mkdir -p /tmp/linux-install/boot/&lt;br /&gt;3. make INSTALL_PATH=/tmp/linux-install/boot/ install&lt;br /&gt;4. mkdir -p /tmp/linux-install/lib/modules/&lt;br /&gt;5. make INSTALL_MOD_PATH=/tmp/linux-install/ modules_install (this will also install firmware)&lt;br /&gt;6. mkdir -p /tmp/linux-install/usr/&lt;br /&gt;7. make INSTALL_HDR_PATH=/tmp/linux-install/usr/ headers_install&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;At this point, the /tmp/linux-install/ will have a complete installation of the Linux kernel.&lt;br /&gt;Create a kernelhack.spec file that only have the %files section like below (the easiest way to get this sort of .spec file is to hijack it from alien).&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;Name: kernelhack &lt;br /&gt;Version: 2.6.32.rc6&lt;br /&gt;Release: netbook&lt;br /&gt;Summary: Kernel RPM created by packaging the 'make install' result&lt;br /&gt;&lt;br /&gt;Group:  System Environment/Kernel&lt;br /&gt;License: GPLv2&lt;br /&gt;URL:  http://www.kernel.org&lt;br /&gt;&lt;br /&gt;%description&lt;br /&gt;The kernel package contains only the files under /boot such as vmlinuz and System.map&lt;br /&gt;&lt;br /&gt;%files&lt;br /&gt;# %defattr(-,root,root,-)&lt;br /&gt;# %doc&lt;br /&gt;%dir /boot&lt;br /&gt;/boot/*&lt;br /&gt;%dir /lib/firmware&lt;br /&gt;/lib/firmware/*&lt;br /&gt;%dir /lib/modules&lt;br /&gt;/lib/modules/*&lt;br /&gt;%dir /usr/include&lt;br /&gt;/usr/include/*&lt;br /&gt;&lt;br /&gt;%changelog&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;In addition, add the below to your .rpmmacros:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;%_buildrootdir  /tmp/&lt;br /&gt;%buildroot       %{_buildrootdir}/linux-install/&lt;br /&gt;&lt;br /&gt;%_rpmdir /tmp/RPMS/&lt;br /&gt;&lt;br /&gt;%_nonzero_exit_pkgcheck_terminate_build        0&lt;br /&gt;%_unpackaged_files_terminate_build 0&lt;br /&gt;%_missing_doc_files_terminate_build 0&lt;br /&gt;%_binaries_in_noarch_packages_terminate_build 0&lt;br /&gt;%_missing_build_ids_terminate_build    0&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Finally, just do a 'rpmbuild -bb kernelhack.spec'&lt;br /&gt;When a modification is needed, just repeat the 'make install' steps above to install it to /tmp/linux-install/ and rerun the rpmbuild.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-8589948374997732471?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-08T12:23:23.611+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>My new USB video class webcam, EXOO M031</title><link>http://weichong78.blogspot.com/2009/10/my-new-usb-video-class-webcam-exoo-m031.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Sat, 10 Oct 2009 04:48:37 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-8686517869841701693</guid><description>I just bought a webcam to try out some applications in my Linux laptop.  To prevent from buying yet-another-win-only-product, I did my home work and print the supported webcam list for the gspca and uvc driver with me.  In fact, I brought along my laptop with me to test it out. As I expected, there are only very limited choices in my local store, and the first reaction from the store keeper is always say NO to the L word before he even check it out.  But I insisted to try them out.  To my suprise there is a low-end webcam that has a penguin logo on its box.  So, I tried that and viola, it worked without any extra configuration.  So, I purchased that.  &lt;br /&gt;The box didn't show the brand name but it seems that both my Debian (with latest git kernel) and Ubuntu is able to detect and drive it with the uvcvideo driver.&lt;br /&gt;I'm happy that the manufacturer, EXOO produce something that works across OS using the USB Video Class UVC standard and thus would like to introduce this to those of you who read my blog, thereby encouraging you to support manufacturer that produce such Linux friendly product.  Here is a link to the &lt;a href="http://www.exoo.cn/en/product_details.asp?id=1076"&gt;webcam website&lt;/a&gt;.&lt;br /&gt;Good on you, EXOO!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-8686517869841701693?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-10T19:48:37.000+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><title>get_current task_struct, stack pointer and FS segment, part 2</title><link>http://weichong78.blogspot.com/2009/09/getcurrent-taskstruct-stack-pointer-and_18.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Fri, 18 Sep 2009 08:17:58 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-2408490198980089458</guid><description>The new utilization of per cpu area to locate current task_struct really got me confused for a while.  This has motivated me to "use the source" (and objdump the binary) again.&lt;br /&gt;&lt;br /&gt;The per cpu area is located via the 27th entry of the GDT.  One can inspect this by dumping out the GDT using, say, kernel debugger or anything.  I use the free dtdumper tool by cr0.org.&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;GDT size: 0xFF (32 entries), GDT LA: 0xC3C00000&lt;br /&gt;&lt;br /&gt;(#027) 0xD8 028F937A8000FFFF  Data  D/B=16bts  AVL=0  Present  DPL=0  TYPE= eWA  BASE=0x027A8000  LIMIT=0xFFFFFFFF&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;This segment is defined here in the source:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;arch/x86/include/asm/segment.h:&lt;br /&gt;&lt;br /&gt; *  ------- start of kernel segments:&lt;br /&gt; *  12 - kernel code segment            &lt;==== new cacheline&lt;br /&gt;#define GDT_ENTRY_KERNEL_BASE   12&lt;br /&gt; *  27 - per-cpu                        [ offset to per-cpu data area ]&lt;br /&gt;#define GDT_ENTRY_PERCPU                        (GDT_ENTRY_KERNEL_BASE + 15)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The code that setup this segment entry is here:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;arch/x86/kernel/setup_percpu.c:&lt;br /&gt;&lt;br /&gt;static inline void setup_percpu_segment(int cpu)&lt;br /&gt;        write_gdt_entry(get_cpu_gdt_table(cpu),&lt;br /&gt;                        GDT_ENTRY_PERCPU, &amp;gdt, DESCTYPE_S);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;which was called from here, in the same source file:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;arch/x86/kernel/setup_percpu.c:&lt;br /&gt;&lt;br /&gt;void __init setup_per_cpu_areas(void)&lt;br /&gt;        /* alrighty, percpu areas up and running */&lt;br /&gt;        delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;&lt;br /&gt;        for_each_possible_cpu(cpu) {&lt;br /&gt;                per_cpu_offset(cpu) = delta + pcpu_unit_offsets[cpu];&lt;br /&gt;                per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu);&lt;br /&gt;                per_cpu(cpu_number, cpu) = cpu;&lt;br /&gt;                setup_percpu_segment(cpu);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The per_cpu_offset is actually a macro that expand to the __per_cpu_offset array defined in setup_percpu.c itself:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;arch/x86/kernel/setup_percpu.c:&lt;br /&gt;&lt;br /&gt;unsigned long __per_cpu_offset[NR_CPUS] __read_mostly = {&lt;br /&gt;        [0 ... NR_CPUS-1] = BOOT_PERCPU_OFFSET,&lt;br /&gt;};&lt;br /&gt;EXPORT_SYMBOL(__per_cpu_offset);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;with the help from:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;include/asm-generic/percpu.h:&lt;br /&gt;&lt;br /&gt;#ifdef CONFIG_SMP&lt;br /&gt;/*&lt;br /&gt; * per_cpu_offset() is the offset that has to be added to a&lt;br /&gt; * percpu variable to get to the instance for a certain processor.&lt;br /&gt; *&lt;br /&gt; * Most arches use the __per_cpu_offset array for those offsets but&lt;br /&gt; * some arches have their own ways of determining the offset (x86_64, s390).&lt;br /&gt; */&lt;br /&gt;#ifndef __per_cpu_offset&lt;br /&gt;extern unsigned long __per_cpu_offset[NR_CPUS];&lt;br /&gt;#define per_cpu_offset(x) (__per_cpu_offset[x])&lt;br /&gt;#endif&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;If one notice the GDT dump above, one would be curious about BASE=0x027A8000, since such linear address would be way below the 0xc0000000 kernel address.  To understand this, we have to understand the line&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;        delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;in the arch/x86/kernel/setup_percpu.c code above.&lt;br /&gt;&lt;br /&gt;The variable pcpu_base_addr is define here:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;mm/percpu.c:&lt;br /&gt;&lt;br /&gt;/* the address of the first chunk which starts with the kernel static area */&lt;br /&gt;void *pcpu_base_addr __read_mostly;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;while __per_cpu_start is the start of a section, added by the linker during the kernel image build, as can be seen in the linker script here:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;arch/x86/kernel/vmlinux.lds:&lt;br /&gt;&lt;br /&gt; . = ALIGN((1 &lt;&lt; 12)); .data.percpu : AT(ADDR(.data.percpu) - 0xC0000000) { __per_cpu_load = .; __per_cpu_start = .; *(.data.percpu.first) *(.data.percpu.page_aligned) *(.data.percpu) *(.data.percpu.shared_aligned) __per_cpu_end = .; }&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So, in essence, what is store in the BASE portion of the GDT 27th entry, is the offset between the pcpu_base_addr variable (which would of cause have a linear address above 0xC0000000) and the __per_cpu_start introduced during linking.  I believe the delta is needed to compensate for the difference in the link time address and the actual load/run time address.  This offset will correctly offset the processor to locate the run time per cpu variable, such as per_cpu__current_task which points to the current active task_struct.&lt;br /&gt;&lt;br /&gt;To ensure myself of my own findings, I disassemble vmlinux.  And can be seen from the mix C-asm disassembly, &lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;int do_one_initcall(initcall_t fn):&lt;br /&gt;&lt;br /&gt;static __always_inline struct task_struct *get_current(void)&lt;br /&gt;{&lt;br /&gt;        return percpu_read_stable(current_task);&lt;br /&gt;c1001142:       64 a1 54 94 45 c1       mov    %fs:0xc1459454,%eax&lt;br /&gt;/*&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;and as we can see by doing objump -x vmlinux:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;c1459454 g     O .data.percpu 00000004 per_cpu__current_task&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;this is how the current task_struct can be retrieved via the offset stored in 27th entry of GDT.&lt;br /&gt;&lt;br /&gt;By the way, the 27th entry of GDT is accessed by %fs segment register.&lt;br /&gt;&lt;br /&gt;Well, this is what I found out so far by refering to the source in Linux 2.6.31.  Feel free to educate me if what I think I understand is wrong.  Thank you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-2408490198980089458?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-18T23:17:58.872+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>get_current task_struct, stack pointer and FS segment, part 1</title><link>http://weichong78.blogspot.com/2009/09/getcurrent-taskstruct-stack-pointer-and.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Fri, 18 Sep 2009 06:49:41 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-5967594934899969758</guid><description>Recently, I was playing around with some toy kernel code and found out that in arch x86, the get_current() inline function that the 'current' macro expands to whenever we try to access the task_struct of the active running process is no longer the same as previously explained in many Linux kernel books such as Robert Love's Linux Kernel Development and also Bovet's Understanding the Linux Kernel.&lt;br /&gt;What I learn from the books earlier was that the current task_struct can be access via the current thread_info, which can be located using the %esp stack pointer since they share the same 4k (or 8k depends on config) pages.&lt;br /&gt;Currently, for asm-generic/current.h, that method is still there, but for x86, the new method is to utilized the per cpu area.  The change has been around for some time now (and more changes since), as can be detected by git diff as can be seen below:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;git diff 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2..7c3576d261ce046789a7db14f43303f8120910c7 -- include/asm-i386/current.h&lt;br /&gt;&lt;br /&gt;diff --git a/include/asm-i386/current.h b/include/asm-i386/current.h&lt;br /&gt;index d973289..d352485 100644&lt;br /&gt;--- a/include/asm-i386/current.h&lt;br /&gt;+++ b/include/asm-i386/current.h&lt;br /&gt;@@ -1,13 +1,15 @@&lt;br /&gt; #ifndef _I386_CURRENT_H&lt;br /&gt; #define _I386_CURRENT_H&lt;br /&gt; &lt;br /&gt;-#include &lt;linux/thread_info.h&gt;&lt;br /&gt;+#include &lt;linux/compiler.h&gt;&lt;br /&gt;+#include &lt;asm/percpu.h&gt;&lt;br /&gt; &lt;br /&gt; struct task_struct;&lt;br /&gt; &lt;br /&gt;-static inline struct task_struct * get_current(void)&lt;br /&gt;+DECLARE_PER_CPU(struct task_struct *, current_task);&lt;br /&gt;+static __always_inline struct task_struct *get_current(void)&lt;br /&gt; {&lt;br /&gt;-       return current_thread_info()-&gt;task;&lt;br /&gt;+       return x86_read_percpu(current_task);&lt;br /&gt; }&lt;br /&gt;  &lt;br /&gt; #define current get_current()&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;and this one too...&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;git diff 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2..ec7fcaabbfb3c5bd5189f857b6ac7bb9745ef291 -- include/asm-i386/current.h&lt;br /&gt;&lt;br /&gt;diff --git a/include/asm-i386/current.h b/include/asm-i386/current.h&lt;br /&gt;index d973289..5252ee0 100644&lt;br /&gt;--- a/include/asm-i386/current.h&lt;br /&gt;+++ b/include/asm-i386/current.h&lt;br /&gt;@@ -1,13 +1,14 @@&lt;br /&gt; #ifndef _I386_CURRENT_H&lt;br /&gt; #define _I386_CURRENT_H&lt;br /&gt; &lt;br /&gt;-#include &lt;linux/thread_info.h&gt;&lt;br /&gt;+#include &lt;asm/pda.h&gt;&lt;br /&gt;+#include &lt;linux/compiler.h&gt;&lt;br /&gt; &lt;br /&gt; struct task_struct;&lt;br /&gt; &lt;br /&gt;-static inline struct task_struct * get_current(void)&lt;br /&gt;+static __always_inline struct task_struct *get_current(void)&lt;br /&gt; {&lt;br /&gt;-       return current_thread_info()-&gt;task;&lt;br /&gt;+       return read_pda(pcurrent);&lt;br /&gt; }&lt;br /&gt;  &lt;br /&gt; #define current get_current()&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-5967594934899969758?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-18T21:49:41.844+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><title>Playing with Integrated Graphics Device D-state</title><link>http://weichong78.blogspot.com/2009/09/playing-with-integrated-graphics-device.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Sat, 05 Sep 2009 18:19:50 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-6221805877725446355</guid><description>Following my previous toy on switching AC'97 between D3 - D0 states, I was tempted to play with more complex components in my personal laptop.  However, just passing the PCI IDs of my integrated graphics device wouldn't work as the device has more state to maintain then just the PCI config space, I think.  Navigating around further in the kernel source makes me think in terms of utilizing the suspend/resume hook of the DRM (direct rendering manager) kernel codes.  I saw that there is a pci_driver embedded inside the DRM code.  So, I try to use that.  My initial attempts failed, until a friend remind me that the i915 DRM code is not necessarily registering itself as a pci_driver unless Kernel Mode Setting code is being utilized.  So, I try my code under Fedora 11 (kernel 2.6.29.5-191.fc11.i586 and xorg-x11-server-Xorg-1.6.1.901-1.fc11.i586) where the X.org i915 is using KMS and it works!  So, here is my updated toy code:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;/* PCI Power Management D-state test&lt;br /&gt;&lt;br /&gt;* Copyright (c) 31 August 2009 Tan Wei Chong&lt;br /&gt;&lt;br /&gt;* This file is released under the GPLv2 */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;linux/init.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/module.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;linux/pci.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;linux/pci_ids.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;linux/pm.h&amp;gt;&lt;br /&gt;#include &amp;lt;drm/drmP.h&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* default test device was the AC97 controller in the author's laptop */&lt;br /&gt;&lt;br /&gt;#define PCI_DSTATE_VENDOR_ID_DEFAULT PCI_VENDOR_ID_INTEL&lt;br /&gt;&lt;br /&gt;#define PCI_DSTATE_DEVICE_ID_DEFAULT PCI_DEVICE_ID_INTEL_82801DB_5&lt;br /&gt;&lt;br /&gt;#define PCI_DSTATE_BUS_DEFAULT 0x0&lt;br /&gt;&lt;br /&gt;#define PCI_DSTATE_SLOT_DEFAULT 0x1f&lt;br /&gt;&lt;br /&gt;#define PCI_DSTATE_FUNC_DEFAULT 0x5&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static int use_devfn = 0;&lt;br /&gt;&lt;br /&gt;static unsigned short bus = 0;&lt;br /&gt;&lt;br /&gt;static unsigned short slot = 0;&lt;br /&gt;&lt;br /&gt;static unsigned short func = 0;&lt;br /&gt;&lt;br /&gt;static unsigned int vendor_id = 0;&lt;br /&gt;&lt;br /&gt;static unsigned int device_id = 0;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static struct pci_dev* pci_dstate_find_dev (void)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt; struct pci_dev *pci_dev;&lt;br /&gt;&lt;br /&gt; pci_dev = NULL;&lt;br /&gt;&lt;br /&gt; if (use_devfn) {&lt;br /&gt;&lt;br /&gt;  if (!bus) bus = PCI_DSTATE_BUS_DEFAULT;&lt;br /&gt;&lt;br /&gt;  if (!slot) slot = PCI_DSTATE_SLOT_DEFAULT;&lt;br /&gt;&lt;br /&gt;  if (!func) func = PCI_DSTATE_FUNC_DEFAULT;&lt;br /&gt;&lt;br /&gt;  printk("pci_dstate_find_dev: bus = %x, slot = %x, func = %x\n", bus, slot, func);&lt;br /&gt;&lt;br /&gt;  pci_dev = pci_get_bus_and_slot(bus, PCI_DEVFN(slot, func));&lt;br /&gt;&lt;br /&gt; } else {&lt;br /&gt;&lt;br /&gt;  if (!vendor_id) vendor_id = PCI_DSTATE_VENDOR_ID_DEFAULT;&lt;br /&gt;&lt;br /&gt;  if (!device_id) device_id = PCI_DSTATE_DEVICE_ID_DEFAULT;&lt;br /&gt;&lt;br /&gt;  printk("pci_dstate_find_dev: vendor_id = %x, device_id = %x\n", vendor_id, device_id);&lt;br /&gt;&lt;br /&gt;  pci_dev = pci_get_device(vendor_id, device_id, NULL);&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; if (pci_dev) {&lt;br /&gt;&lt;br /&gt;  printk("pci_dstate_find_dev: pci_dev-&gt;vendor = %x, pci_dev-&gt;device = %x\n", pci_dev-&gt;vendor, pci_dev-&gt;device);&lt;br /&gt;&lt;br /&gt;  printk("pci_dstate_find_dev: pci_dev-&gt;bus-&gt;number = %x, pci_dev-&gt;devfn = %x (PCI_SLOT = %x, PCI_FUNC = %x)\n",&lt;br /&gt;&lt;br /&gt;   pci_dev-&gt;bus-&gt;number, pci_dev-&gt;devfn, PCI_SLOT(pci_dev-&gt;devfn), PCI_FUNC(pci_dev-&gt;devfn));&lt;br /&gt;&lt;br /&gt;  printk("pci_dstate_find_dev: pci_dev-&gt;class = %x\n", pci_dev-&gt;class);&lt;br /&gt;&lt;br /&gt; } else {&lt;br /&gt;&lt;br /&gt;  printk("pci_dstate_find_dev: pci_dev is NULL!\n");&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; return pci_dev;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static int gfx_d3hot (struct pci_dev* pci_dev)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt; pm_message_t state;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; if (pci_dev &amp;&amp; pci_dev-&gt;driver &amp;&amp; pci_dev-&gt;driver-&gt;suspend) {&lt;br /&gt;&lt;br /&gt;  state.event = PM_EVENT_SUSPEND;&lt;br /&gt;&lt;br /&gt;  return pci_dev-&gt;driver-&gt;suspend(pci_dev, state);&lt;br /&gt;&lt;br /&gt; } else {&lt;br /&gt;&lt;br /&gt;  if (!pci_dev)&lt;br /&gt;&lt;br /&gt;   printk("gfx_d3hot: pci_dev is NULL, do nothing\n");&lt;br /&gt;&lt;br /&gt;  else if (!pci_dev-&gt;driver)&lt;br /&gt;&lt;br /&gt;   printk("gfx_d3hot: pci_dev-&gt;driver is NULL, do nothing\n");&lt;br /&gt;&lt;br /&gt;  else if (!pci_dev-&gt;driver-&gt;suspend)&lt;br /&gt;&lt;br /&gt;   printk("gfx_d3hot: pci_dev-&gt;driver-&gt;suspend is NULL, do nothing\n");&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static void pci_d3hot (struct pci_dev* pci_dev)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt; pci_power_t power_state;&lt;br /&gt;&lt;br /&gt; power_state = PCI_D3hot;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; if (pci_dev) {&lt;br /&gt;&lt;br /&gt;  pci_save_state(pci_dev);&lt;br /&gt;&lt;br /&gt;  pci_set_power_state(pci_dev, power_state);&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static int gfx_d0 (struct pci_dev* pci_dev)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt; if (pci_dev &amp;&amp; pci_dev-&gt;driver &amp;&amp; pci_dev-&gt;driver-&gt;resume) {&lt;br /&gt;&lt;br /&gt;  return pci_dev-&gt;driver-&gt;resume(pci_dev);&lt;br /&gt;&lt;br /&gt; } else {&lt;br /&gt;&lt;br /&gt;  if (!pci_dev)&lt;br /&gt;&lt;br /&gt;   printk("gfx_d0: pci_dev NULL, do nothing\n");&lt;br /&gt;&lt;br /&gt;  else if (!pci_dev-&gt;driver)&lt;br /&gt;&lt;br /&gt;   printk("gfx_d0: pci_dev-&gt;driver is NULL, do nothing\n");&lt;br /&gt;&lt;br /&gt;  else if (!pci_dev-&gt;driver-&gt;resume)&lt;br /&gt;&lt;br /&gt;   printk("gfx_d0: pci_dev-&gt;driver-&gt;resume is NULL, do nothing\n");&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static void pci_d0 (struct pci_dev* pci_dev)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt; pci_power_t power_state;&lt;br /&gt;&lt;br /&gt; power_state = PCI_D0;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; if (pci_dev) {&lt;br /&gt;&lt;br /&gt;  pci_set_power_state(pci_dev, power_state);&lt;br /&gt;&lt;br /&gt;  pci_restore_state(pci_dev);&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;int __init pci_dstate_init (void)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt; struct pci_dev *pci_dev;&lt;br /&gt;&lt;br /&gt; pci_dev = pci_dstate_find_dev(); &lt;br /&gt;&lt;br /&gt; if (pci_dev-&gt;class == (PCI_CLASS_DISPLAY_VGA &lt;&lt; 8)) {&lt;br /&gt;&lt;br /&gt;  gfx_d3hot(pci_dev);&lt;br /&gt;&lt;br /&gt; } else {&lt;br /&gt;&lt;br /&gt;  pci_d3hot(pci_dev);&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; return 0;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void __exit pci_dstate_exit (void)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt; struct pci_dev *pci_dev;&lt;br /&gt;&lt;br /&gt; pci_dev = pci_dstate_find_dev(); &lt;br /&gt;&lt;br /&gt; if (pci_dev-&gt;class == (PCI_CLASS_DISPLAY_VGA &lt;&lt; 8)) {&lt;br /&gt;&lt;br /&gt;  gfx_d0(pci_dev);&lt;br /&gt;&lt;br /&gt; } else {&lt;br /&gt;&lt;br /&gt;  pci_d0(pci_dev);&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;module_init(pci_dstate_init);&lt;br /&gt;&lt;br /&gt;module_exit(pci_dstate_exit);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;MODULE_PARM_DESC(use_devfn, "true means use bus/slot/func, false means use vendor id and device id");&lt;br /&gt;&lt;br /&gt;module_param(use_devfn, bool, S_IRUGO);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;MODULE_PARM_DESC(bus, "PCI bus number");&lt;br /&gt;&lt;br /&gt;module_param(bus, ushort, S_IRUGO);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;MODULE_PARM_DESC(slot, "PCI device/slot number");&lt;br /&gt;&lt;br /&gt;module_param(slot, ushort, S_IRUGO);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;MODULE_PARM_DESC(func, "PCI device/slot number");&lt;br /&gt;&lt;br /&gt;module_param(func, ushort, S_IRUGO);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;MODULE_PARM_DESC(vendor_id, "PCI vendor ID");&lt;br /&gt;&lt;br /&gt;module_param(vendor_id, uint, S_IRUGO);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;MODULE_PARM_DESC(device_id, "PCI device ID");&lt;br /&gt;&lt;br /&gt;module_param(device_id, uint, S_IRUGO);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;MODULE_LICENSE("GPL");&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-6221805877725446355?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-06T09:19:50.281+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><title>Playing with PCI PM D-state</title><link>http://weichong78.blogspot.com/2009/08/playing-with-pci-pm-d-state.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Mon, 31 Aug 2009 06:01:40 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-4864700317794764180</guid><description>Its been a really long time I haven't post anything.  Yeah, life is busy, and I am lazy :).&lt;br /&gt;About that I'm just thinking of just putting a test program I play with tonight to shut off my personal home laptop's PCI device (which I just arbitrarily chose my AC'97 audio controller for its simplicity).&lt;br /&gt;I use speaker-test and lspci to verify that the device does in fact switch between D0 and D3.&lt;br /&gt;Long story short, here is my hobbyist test program :). &lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;/* PCI Power Management D-state test &lt;br /&gt; * Copyright (c) 31 August 2009 Tan Wei Chong&lt;br /&gt; * This file is released under the GPLv2 */&lt;br /&gt;&lt;br /&gt;#include &amp;lt;linux/init.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/module.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/pci.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/pci_ids.h&amp;gt;&lt;br /&gt;&lt;br /&gt;/* default test device was the AC97 controller in the author's laptop */&lt;br /&gt;#define PCI_DSTATE_VENDOR_ID_DEFAULT PCI_VENDOR_ID_INTEL&lt;br /&gt;#define PCI_DSTATE_DEVICE_ID_DEFAULT PCI_DEVICE_ID_INTEL_82801DB_5&lt;br /&gt;#define PCI_DSTATE_BUS_DEFAULT 0x0&lt;br /&gt;#define PCI_DSTATE_SLOT_DEFAULT 0x1f&lt;br /&gt;#define PCI_DSTATE_FUNC_DEFAULT 0x5&lt;br /&gt;&lt;br /&gt;static bool use_devfn = false;&lt;br /&gt;static unsigned short bus = 0;&lt;br /&gt;static unsigned short slot = 0;&lt;br /&gt;static unsigned short func = 0;&lt;br /&gt;static unsigned int vendor_id = 0;&lt;br /&gt;static unsigned int device_id = 0;&lt;br /&gt;static struct pci_dev *pci_dev;&lt;br /&gt;&lt;br /&gt;int __init pci_dstate_init (void)&lt;br /&gt;{&lt;br /&gt; pci_power_t power_state;&lt;br /&gt;&lt;br /&gt; power_state = PCI_D3hot;&lt;br /&gt;&lt;br /&gt; if (use_devfn) {&lt;br /&gt;  if (!bus) bus = PCI_DSTATE_BUS_DEFAULT;&lt;br /&gt;  if (!slot) slot = PCI_DSTATE_SLOT_DEFAULT;&lt;br /&gt;  if (!func) func = PCI_DSTATE_FUNC_DEFAULT;&lt;br /&gt;  printk("pci_dstate_init: bus = %x, slot = %x, func = %x\n", bus, slot, func);&lt;br /&gt;  pci_dev = pci_get_bus_and_slot(bus, PCI_DEVFN(slot, func));&lt;br /&gt; } else {&lt;br /&gt;  if (!vendor_id) vendor_id = PCI_DSTATE_VENDOR_ID_DEFAULT;&lt;br /&gt;  if (!device_id) device_id = PCI_DSTATE_DEVICE_ID_DEFAULT;&lt;br /&gt;  printk("pci_dstate_init: vendor_id = %x, device_id = %x\n", vendor_id, device_id);&lt;br /&gt;  pci_dev = pci_get_device(vendor_id, device_id, NULL);&lt;br /&gt; }&lt;br /&gt; if (!pci_dev) {&lt;br /&gt;  printk("pci_dstate_init: pci_dev is NULL!\n");&lt;br /&gt;  goto init_finish;  &lt;br /&gt; }&lt;br /&gt; printk("pci_dstate_init: pci_dev-&gt;vendor = %x, pci_dev-&gt;device = %x\n", pci_dev-&gt;vendor, pci_dev-&gt;device);&lt;br /&gt; printk("pci_dstate_init: pci_dev-&gt;bus-&gt;number = %x, pci_dev-&gt;devfn = %x (PCI_SLOT = %x, PCI_FUNC = %x)\n", &lt;br /&gt;  pci_dev-&gt;bus-&gt;number, pci_dev-&gt;devfn, PCI_SLOT(pci_dev-&gt;devfn), PCI_FUNC(pci_dev-&gt;devfn));&lt;br /&gt; pci_save_state(pci_dev);&lt;br /&gt; pci_set_power_state(pci_dev, power_state);&lt;br /&gt;init_finish:&lt;br /&gt; printk("pci_dstate_init return\n");&lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void __exit pci_dstate_exit (void)&lt;br /&gt;{&lt;br /&gt; pci_power_t power_state;&lt;br /&gt;&lt;br /&gt; power_state = PCI_D0;&lt;br /&gt; if (!pci_dev) {&lt;br /&gt;  printk("pci_dstate_exit: pci_dev is NULL!\n");&lt;br /&gt;  goto exit_finish;&lt;br /&gt; }&lt;br /&gt; pci_set_power_state(pci_dev, power_state);&lt;br /&gt; pci_restore_state(pci_dev);&lt;br /&gt;exit_finish:&lt;br /&gt; printk("pci_dstate_exit return\n");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;module_init(pci_dstate_init);&lt;br /&gt;module_exit(pci_dstate_exit);&lt;br /&gt;&lt;br /&gt;MODULE_PARM_DESC(use_devfn, "true means use bus/slot/func, false means use vendor id and device id");&lt;br /&gt;module_param(use_devfn, bool, S_IRUGO);&lt;br /&gt;&lt;br /&gt;MODULE_PARM_DESC(bus, "PCI bus number");&lt;br /&gt;module_param(bus, ushort, S_IRUGO);&lt;br /&gt;&lt;br /&gt;MODULE_PARM_DESC(slot, "PCI device/slot number");&lt;br /&gt;module_param(slot, ushort, S_IRUGO);&lt;br /&gt;&lt;br /&gt;MODULE_PARM_DESC(func, "PCI device/slot number");&lt;br /&gt;module_param(func, ushort, S_IRUGO);&lt;br /&gt;&lt;br /&gt;MODULE_PARM_DESC(vendor_id, "PCI vendor ID");&lt;br /&gt;module_param(vendor_id, uint, S_IRUGO);&lt;br /&gt;&lt;br /&gt;MODULE_PARM_DESC(device_id, "PCI device ID");&lt;br /&gt;module_param(device_id, uint, S_IRUGO);&lt;br /&gt;&lt;br /&gt;MODULE_LICENSE("GPL");&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-4864700317794764180?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-31T21:01:40.949+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><title>exploring page cache and picking up oops debugging</title><link>http://weichong78.blogspot.com/2008/10/exploring-page-cache-and-picking-up.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Wed, 22 Oct 2008 05:26:28 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-374640883146604750</guid><description>A while ago, I wrote a small toy kernel module to understand how a process interact with page cache after accessing a file, to verify what I have learn from the great ULK3:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;#include &amp;lt;linux/module.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/init.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/fs.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/cdev.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/sched.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/file.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/pagemap.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/highmem.h&amp;gt;&lt;br /&gt;#include &amp;lt;asm/uaccess.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#define FILEPROBE_MAJOR 200&lt;br /&gt;#define FILEPROBE_MINOR 0&lt;br /&gt;&lt;br /&gt;struct fileprobe {&lt;br /&gt; int qpid;&lt;br /&gt; dev_t dev;&lt;br /&gt; struct cdev cdev;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;struct fileprobe fp;&lt;br /&gt;&lt;br /&gt;static int fileprobe_open (struct inode *inode, struct file  *file)&lt;br /&gt;{&lt;br /&gt; printk("fileprobe_open\n");&lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static ssize_t fileprobe_read (struct file* file, char __user *buf, size_t count, loff_t *ppos)&lt;br /&gt;{&lt;br /&gt; printk("fileprobe_read\n");&lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void fileprobe_queryfile (struct file* qfile)&lt;br /&gt;{&lt;br /&gt; struct page* qpage;&lt;br /&gt; char* qcontent;&lt;br /&gt;&lt;br /&gt; printk("fileprobe_queryfile\n");&lt;br /&gt; printk("find_get_page 0\n");&lt;br /&gt; qpage = find_get_page(qfile-&gt;f_mapping, 0);&lt;br /&gt; if (NULL != qpage) {&lt;br /&gt;  qcontent = (char*)kmap(qpage);&lt;br /&gt;  if (NULL != qcontent) {&lt;br /&gt;   printk("  the content of 1st page is [%c%c%c%c]\n", qcontent[0], qcontent[1], qcontent[2], qcontent[3]);&lt;br /&gt;   kunmap((void*)qcontent);&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; printk("find_get_page 1\n");&lt;br /&gt; qpage = find_get_page(qfile-&gt;f_mapping, 1);&lt;br /&gt; if (NULL != qpage) {&lt;br /&gt;  qcontent = (char*)kmap(qpage);&lt;br /&gt;  if (NULL != qcontent) {&lt;br /&gt;   printk("  the content of 2nd page is [%c%c%c%c]\n", qcontent[0], qcontent[1], qcontent[2], qcontent[3]);&lt;br /&gt;   kunmap((void*)qcontent);&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static ssize_t fileprobe_write (struct file* file, const char __user *buf, size_t count, loff_t *ppos)&lt;br /&gt;{&lt;br /&gt; struct task_struct *qtask;&lt;br /&gt; int fd_nr;&lt;br /&gt; struct file* qfile;&lt;br /&gt;&lt;br /&gt; printk("fileprobe_write\n");&lt;br /&gt; get_user(fp.qpid, (int __user *)buf);&lt;br /&gt;&lt;br /&gt; for_each_process(qtask) {&lt;br /&gt;  if(qtask-&gt;pid == fp.qpid) {&lt;br /&gt;   printk("task_struct found for PID %d, %s\n", qtask-&gt;pid, qtask-&gt;comm);&lt;br /&gt;   for(fd_nr = 0; fd_nr &lt;&gt;files-&gt;fdt-&gt;max_fds; fd_nr++) {&lt;br /&gt;    qfile = qtask-&gt;files-&gt;fdt-&gt;fd[fd_nr];&lt;br /&gt;    if(qfile != NULL) {&lt;br /&gt;     printk("  fd_nr is %d, dentry-&gt;d_iname is %s\n", fd_nr, qfile-&gt;f_path.dentry-&gt;d_iname);&lt;br /&gt;     if(0 == strcmp(qfile-&gt;f_path.dentry-&gt;d_iname,"fileprobe.log")) {&lt;br /&gt;      fileprobe_queryfile(qfile);&lt;br /&gt;     }&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;struct file_operations f_ops = {&lt;br /&gt; .open = fileprobe_open,&lt;br /&gt; /* .release = fileprobe_release, */&lt;br /&gt; .read = fileprobe_read,&lt;br /&gt; .write = fileprobe_write&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int __init fileprobe_init (void)&lt;br /&gt;{&lt;br /&gt; int ret;&lt;br /&gt; printk("fileprobe_init\n");&lt;br /&gt; cdev_init(&amp;amp;fp.cdev, &amp;amp;f_ops);&lt;br /&gt; fp.dev = MKDEV(FILEPROBE_MAJOR, FILEPROBE_MINOR);&lt;br /&gt; ret = register_chrdev_region(fp.dev, 1, "fileprobe");&lt;br /&gt; ret = cdev_add(&amp;amp;fp.cdev, fp.dev, 1);&lt;br /&gt; if (ret != 0) goto err1;&lt;br /&gt; return 0;&lt;br /&gt;err1:&lt;br /&gt; unregister_chrdev_region(fp.dev, 1);&lt;br /&gt; return -1;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void __exit fileprobe_exit (void)&lt;br /&gt;{&lt;br /&gt; cdev_del(&amp;amp;fp.cdev);&lt;br /&gt; unregister_chrdev_region(fp.dev, 1);&lt;br /&gt; printk("fileprobe_exit\n");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;module_init(fileprobe_init);&lt;br /&gt;module_exit(fileprobe_exit);&lt;br /&gt;&lt;br /&gt;MODULE_LICENSE("GPL");&lt;br /&gt;&lt;/asm&gt;&lt;/linux&gt;&lt;/linux&gt;&lt;/linux&gt;&lt;/linux&gt;&lt;/linux&gt;&lt;/linux&gt;&lt;/linux&gt;&lt;/linux&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Basically, it is a simple character device module that accept a PID as argument.  With that PID, it search for the task_struct from the task list.  It then search the task_struct's file descriptor table to look for an open file with the file name (from dentry) "fileprobe.log".  With the located struct file, it try to look for the corresponding struct address_space through f_mapping.  The address_space structure has a (if I remember correctly) red-black tree of struct page which identify which physical page frame host the file content.  The module utilizes the kernel function find_get_page() to locate the page frames by passing the 4k page order as the second argument.  It then use kmap to obtain a virtual address of the physical page and use printk to display partial content of "fileprobe.log".&lt;br /&gt;&lt;br /&gt;Now this whole thing is very toyish and canned for learning purpose only.  The content of "fileprobe.log" is exactly 8k.  The first 4k starts with 3 characters "1st" follow by all 'X' characters while the second 4k starts with 3 characters "2nd" follow by all 'Y', to make it easy for verification.  Basically, such a file can easily be created by a perl command line like&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;perl -e 'print "X"x4096'&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;with the first 3 characters replaced (vim recommended :-).&lt;br /&gt;&lt;br /&gt;I then conduct the experiment by using less to open the "fileprobe.log" file, obtain the PID of the less process and write the value to the device node of the kernel module using a user space program like:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;#include &lt;unistd.h&gt;&lt;br /&gt;#include &lt;fcntl.h&gt;&lt;br /&gt;#include &lt;stdio.h&gt;&lt;br /&gt;&lt;br /&gt;int main (int argc, char** argv)&lt;br /&gt;{&lt;br /&gt; int qpid = atoi(argv[1]);&lt;br /&gt; printf("qpid is %d\n", qpid);&lt;br /&gt; int fd = open("./fileprobe", O_WRONLY);&lt;br /&gt; write(fd, &amp;amp;qpid, sizeof(qpid));&lt;br /&gt; close(fd);&lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/stdio.h&gt;&lt;/fcntl.h&gt;&lt;/unistd.h&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;With the description above, all went well.  But the above kernel module was not the original version, which had the below difference:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;--- fileprobe.c 2008-10-21 21:12:23.000000000 +0800&lt;br /&gt;+++ fileprobe.c.orig    2008-10-21 21:11:07.000000000 +0800&lt;br /&gt;@@ -42,7 +42,7 @@&lt;br /&gt;       if (NULL != qpage) {&lt;br /&gt;               qcontent = (char*)kmap(qpage);&lt;br /&gt;               if (NULL != qcontent) {&lt;br /&gt;-                       printk("  the content of 1st page is [%c%c%c%c]\n", qcontent[0], qcontent[1], qcontent[2], qcontent[3]);&lt;br /&gt;+                       printk("  the content of 1st page is [%s]\n", qcontent);&lt;br /&gt;                       kunmap((void*)qcontent);&lt;br /&gt;               }&lt;br /&gt;       }&lt;br /&gt;@@ -51,7 +51,7 @@&lt;br /&gt;       if (NULL != qpage) {&lt;br /&gt;               qcontent = (char*)kmap(qpage);&lt;br /&gt;               if (NULL != qcontent) {&lt;br /&gt;-                       printk("  the content of 2nd page is [%c%c%c%c]\n", qcontent[0], qcontent[1], qcontent[2], qcontent[3]);&lt;br /&gt;+                       printk("  the content of 2nd page is [%s]\n", qcontent);&lt;br /&gt;                       kunmap((void*)qcontent);&lt;br /&gt;               }&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;This original version actually gave an OOPs the first time I tried, which looks like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;[  852.962496] fileprobe_init&lt;br /&gt;[  853.794718] fileprobe_open&lt;br /&gt;[  853.794728] fileprobe_write&lt;br /&gt;[  853.794753] task_struct found for PID 9096, less&lt;br /&gt;[  853.794756]   fd_nr is 0, dentry-&gt;d_iname is tty2&lt;br /&gt;[  853.794758]   fd_nr is 1, dentry-&gt;d_iname is tty2&lt;br /&gt;[  853.794761]   fd_nr is 2, dentry-&gt;d_iname is tty2&lt;br /&gt;[  853.794763]   fd_nr is 3, dentry-&gt;d_iname is tty&lt;br /&gt;[  853.794765]   fd_nr is 4, dentry-&gt;d_iname is fileprobe.log&lt;br /&gt;[  853.794767] fileprobe_queryfile&lt;br /&gt;[  853.794769] find_get_page 0&lt;br /&gt;[  853.794810] BUG: unable to handle kernel paging request at virtual address ffa0b000&lt;br /&gt;[  853.794813] printing eip: c021a6f6 *pde = 00004067 *pte = 00000000&lt;br /&gt;[  853.794819] Oops: 0000 [#1] SMP&lt;br /&gt;[  853.794898] Modules linked in: fileprobe michael_mic arc4 ecb blkcipher ieee80211_crypt_tkip appletalk ax25 ipx p8023 binfmt_misc rfcomm l2cap bluetooth uinput ppdev i915 drm ipv6 sbs container sbshc dock cpufreq_conservative cpufreq_ondemand cpufreq_userspace cpufreq_powersave cpufreq_stats freq_table iptable_filter ip_tables x_tables aes_i586 dm_crypt dm_mod lp af_packet pcmcia battery ac snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm_oss snd_mixer_oss snd_pcm psmouse ipw2200 serio_raw yenta_socket rsrc_nonstatic pcmcia_core ieee80211 ieee80211_crypt snd_seq_dummy video output snd_seq_oss snd_seq_midi snd_rawmidi snd_seq_midi_event button snd_seq snd_timer snd_seq_device intel_agp thinkpad_acpi nvram evdev agpgart parport_pc parport shpchp pci_hotplug iTCO_wdt iTCO_vendor_support snd soundcore snd_page_alloc pcspkr ext3 jbd mbcache sg sr_mod cdrom sd_mod ata_generic pata_acpi ata_piix e100 mii libata scsi_mod ehci_hcd uhci_hcd usbcore thermal processor fan fbcon tileblit font bitblit softcursor fuse&lt;br /&gt;[  853.797243]&lt;br /&gt;[  853.797281] Pid: 9146, comm: fileprobe_user Not tainted (2.6.24-19-generic #1)&lt;br /&gt;[  853.797343] EIP: 0060:[&lt;c021a6f6&gt;] EFLAGS: 00010097 CPU: 0&lt;br /&gt;[  853.797392] EIP is at strnlen+0x6/0x20&lt;br /&gt;[  853.797433] EAX: ffa0b000 EBX: c048e93e ECX: ffa0a000 EDX: ffffeffe&lt;br /&gt;[  853.797479] ESI: ffa0a000 EDI: 00000000 EBP: ffffffff ESP: ebb97e88&lt;br /&gt;&lt;br /&gt;[  853.797525]  DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068&lt;br /&gt;[  853.797570] Process fileprobe_user (pid: 9146, ti=ebb96000 task=ea3dc5c0 task.ti=ebb96000)&lt;br /&gt;[  853.797619] Stack: c0219c99 000c2091 00000000 0000000a 00000006 ffffffff 00000001 00000400&lt;br /&gt;[  853.797848]        c048e920 0000000a c048ed20 ffa0a000 ffffffff ffffffff f8e1731b 00000400&lt;br /&gt;[  853.798075]        ffa0a000 ea308b80 00000000 c0219f14 ebb97f68 ea1e6600 c012ce7c ebb97f64&lt;br /&gt;[  853.798303] Call Trace:&lt;br /&gt;[  853.798372]  [&lt;c0219c99&gt;] vsnprintf+0x459/0x610&lt;br /&gt;[  853.798453]  [&lt;c0219f14&gt;] vscnprintf+0x14/0x20&lt;br /&gt;[  853.798519]  [&lt;c012ce7c&gt;] vprintk+0x5c/0x380&lt;br /&gt;[  853.798591]  [&lt;c017a8d2&gt;] set_page_address+0xa2/0x160&lt;br /&gt;[  853.798663]  [&lt;c017ad4f&gt;] kmap_high+0x18f/0x1b0&lt;br /&gt;[  853.798732]  [&lt;c012d1bb&gt;] printk+0x1b/0x20&lt;br /&gt;[  853.798795]  [&lt;f8e17157&gt;] fileprobe_write+0x117/0x180 [fileprobe]&lt;br /&gt;[  853.798866]  [&lt;f8e17040&gt;] fileprobe_write+0x0/0x180 [fileprobe]&lt;br /&gt;[  853.798931]  [&lt;c01921b9&gt;] vfs_write+0xb9/0x170&lt;br /&gt;[  853.799000]  [&lt;c01928f1&gt;] sys_write+0x41/0x70&lt;br /&gt;[  853.799067]  [&lt;c01043c2&gt;] sysenter_past_esp+0x6b/0xa9&lt;br /&gt;[  853.799143]  =======================&lt;br /&gt;[  853.799182] Code: 90 8d 74 26 00 85 c9 57 89 c7 89 d0 74 05 f2 ae 75 01 4f 89 f8 5f c3 8d b4 26 00 00 00 00 8d bc 27 00 00 00 00 89 c1 89 c8 eb 06 &lt;80&gt; 38 00 74 07 40 4a 83 fa ff 75 f4 29 c8 c3 90 90 90 90 90 90&lt;br /&gt;[  853.800471] EIP: [&lt;c021a6f6&gt;] strnlen+0x6/0x20 SS:ESP 0068:ebb97e88&lt;br /&gt;[  853.800555] ---[ end trace 45550c129f3be6fa ]---&lt;br /&gt;&lt;/c021a6f6&gt;&lt;/c01043c2&gt;&lt;/c01928f1&gt;&lt;/c01921b9&gt;&lt;/f8e17040&gt;&lt;/f8e17157&gt;&lt;/c012d1bb&gt;&lt;/c017ad4f&gt;&lt;/c017a8d2&gt;&lt;/c012ce7c&gt;&lt;/c0219f14&gt;&lt;/c0219c99&gt;&lt;/c021a6f6&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The OOPs actually puzzled me for a while, until I talked to a mighty parrot this afternoon, and he noticed the "strnlen" in the OOPs, which I was careless enough to missed that obvious hint, thinking that it could be related instead to kmap, all these while, silly me.&lt;br /&gt;&lt;br /&gt;So, go along with that hint, I tried to modify the module which looks like the final version above, and yippie, it worked, with the following dmesg instead:&lt;br /&gt;&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;[  686.833604] fileprobe_init&lt;br /&gt;[  724.422097] fileprobe_open&lt;br /&gt;[  724.422107] fileprobe_write&lt;br /&gt;[  724.422139] task_struct found for PID 7564, less&lt;br /&gt;[  724.422142]   fd_nr is 0, dentry-&gt;d_iname is 1&lt;br /&gt;[  724.422144]   fd_nr is 1, dentry-&gt;d_iname is 1&lt;br /&gt;[  724.422146]   fd_nr is 2, dentry-&gt;d_iname is 1&lt;br /&gt;[  724.422148]   fd_nr is 3, dentry-&gt;d_iname is tty&lt;br /&gt;[  724.422151]   fd_nr is 4, dentry-&gt;d_iname is fileprobe.log&lt;br /&gt;[  724.422153] fileprobe_queryfile&lt;br /&gt;[  724.422154] find_get_page 0&lt;br /&gt;[  724.422157]   the content of 1st page is [1stX]&lt;br /&gt;[  724.422159] find_get_page 1&lt;br /&gt;[  724.422161]   the content of 2nd page is [2ndY]&lt;br /&gt;[  724.422163]   fd_nr is 11, dentry-&gt;d_iname is&lt;br /&gt;[  724.422166]   fd_nr is 62, dentry-&gt;d_iname is&lt;br /&gt;[  724.422168]   fd_nr is 63, dentry-&gt;d_iname is&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Notice the content of the page starts with "1stX" and the second with "2ndY"?  Well, looks like what I read in ULK3 is true.&lt;br /&gt;&lt;br /&gt;By the way, on an unrelated account, the mighty parrot also told me that /etc in Linux stands for "errata configuration" and /usr stands for "UNIX service resource". :-)&lt;br /&gt;&lt;br /&gt;Ok, it is getting late, and I'm tired, so that's all I'm going to dump in this post for now.  If there is any error you notice, please do drop me a comment or email so that I can correct them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-374640883146604750?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-22T20:26:28.630+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>objdump vmlinux</title><link>http://weichong78.blogspot.com/2008/10/objdump-vmlinux.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Tue, 14 Oct 2008 05:31:45 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-4877237226505221758</guid><description>Being able to quickly figure out which part of the kernel source code correspond to the binary (in memory image of) running kernel is always handy, especially when debugging a faulty/oops/crashing system.&lt;br /&gt;A while ago, I used objdump -d -S on the .ko file of the driver I compiled which would intersperse my driver source with the .ko binary.  Thinking along that line, vmlinux should be able to give us similar output with the kernel source code.  After searching around in the web, I found this &lt;a href="http://www.fieldses.org/%7Ebfields/kernel/assembly_notes.txt"&gt;site&lt;/a&gt; that confirms this.&lt;br /&gt;I tried objdump -d -S vmlinux and got a huge 65MB text file that list what I have expected, part of it looks like this:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;vmlinux:     file format elf32-i386&lt;br /&gt;&lt;br /&gt;Disassembly of section .text.head:&lt;br /&gt;&lt;br /&gt;c0100000 &lt;_text&gt;:&lt;br /&gt; */&lt;br /&gt;.section .text.head,"ax",@progbits&lt;br /&gt;ENTRY(startup_32)&lt;br /&gt;        /* test KEEP_SEGMENTS flag to see if the bootloader is asking&lt;br /&gt;                us to not reload segments */&lt;br /&gt;        testb $(1&lt;&lt;6), BP_loadflags(%esi)&lt;br /&gt;c0100000:       f6 86 11 02 00 00 40    testb  $0x40,0x211(%esi)&lt;br /&gt;        jnz 2f&lt;br /&gt;c0100007:       75 14                   jne    c010001d &lt;_text+0x1d&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;and this:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;c03453a0 &lt;do_page_fault&gt;:&lt;br /&gt; */&lt;br /&gt;#ifdef CONFIG_X86_64&lt;br /&gt;asmlinkage&lt;br /&gt;#endif&lt;br /&gt;void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)&lt;br /&gt;{&lt;br /&gt;c03453a0:       55                      push   %ebp&lt;br /&gt;c03453a1:       89 e5                   mov    %esp,%ebp&lt;br /&gt;c03453a3:       57                      push   %edi&lt;br /&gt;c03453a4:       56                      push   %esi&lt;br /&gt;c03453a5:       53                      push   %ebx&lt;br /&gt;c03453a6:       83 ec 34                sub    $0x34,%esp&lt;br /&gt;c03453a9:       e8 72 fe db ff          call   c0105220 &lt;mcount&gt;&lt;br /&gt;c03453ae:       89 45 e4                mov    %eax,-0x1c(%ebp)&lt;br /&gt;c03453b1:       89 55 e0                mov    %edx,-0x20(%ebp)&lt;br /&gt;&lt;br /&gt;static inline unsigned long __raw_local_save_flags(void)&lt;br /&gt;{&lt;br /&gt;        unsigned long f;&lt;br /&gt;&lt;br /&gt;        asm volatile(paravirt_alt(PV_SAVE_REGS&lt;br /&gt;c03453b4:       51                      push   %ecx&lt;br /&gt;c03453b5:       52                      push   %edx&lt;br /&gt;c03453b6:       ff 15 bc 78 43 c0       call   *0xc04378bc&lt;br /&gt;c03453bc:       5a                      pop    %edx&lt;br /&gt;c03453bd:       59                      pop    %ecx&lt;br /&gt; * should be a rarely used function, only in places where its&lt;br /&gt; * otherwise impossible to know the irq state, like in traps.&lt;br /&gt; */&lt;br /&gt;static inline void trace_hardirqs_fixup_flags(unsigned long flags)&lt;br /&gt;{&lt;br /&gt;        if (raw_irqs_disabled_flags(flags))&lt;br /&gt;c03453be:       f6 c4 02                test   $0x2,%ah&lt;br /&gt;c03453c1:       0f 85 ea 00 00 00       jne    c03454b1 &lt;do_page_fault+0x111&gt;&lt;br /&gt;                trace_hardirqs_off();&lt;br /&gt;c03453c7:       e8 d4 55 e3 ff          call   c017a9a0 &lt;trace_hardirqs_off&gt;&lt;br /&gt;c03453cc:       64 a1 00 70 4c c0       mov    %fs:0xc04c7000,%eax&lt;br /&gt;c03453d2:       89 45 e8                mov    %eax,-0x18(%ebp)&lt;br /&gt;         * We can fault from pretty much anywhere, with unknown IRQ state.&lt;br /&gt;         */&lt;br /&gt;        trace_hardirqs_fixup();&lt;br /&gt;&lt;br /&gt;        tsk = current;&lt;br /&gt;        mm = tsk-&gt;mm;&lt;br /&gt;c03453d5:       8b 90 b0 00 00 00       mov    0xb0(%eax),%edx&lt;br /&gt;c03453db:       89 d6                   mov    %edx,%esi&lt;br /&gt;c03453dd:       89 55 ec                mov    %edx,-0x14(%ebp)&lt;br /&gt;c03453e0:       83 c6 34                add    $0x34,%esi&lt;br /&gt;        PVOP_VCALL1(pv_cpu_ops.write_cr0, x);&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;This much I have expected.  But something even better that I tried after reading the website is the make .lst file actually works!&lt;br /&gt;I did a:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;make kernel/panic.lst&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;and here is part of the panic.lst that I get in return:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;panic.o:     file format elf32-i386&lt;br /&gt;&lt;br /&gt;Disassembly of section .text:&lt;br /&gt;&lt;br /&gt;c012c3e0 &lt;no_blink&gt;:&lt;br /&gt;        return 1;&lt;br /&gt;}&lt;br /&gt;__setup("panic=", panic_setup);&lt;br /&gt;&lt;br /&gt;static long no_blink(long time)&lt;br /&gt;{&lt;br /&gt;c012c3e0:       55                      push   %ebp&lt;br /&gt;c012c3e1:       89 e5                   mov    %esp,%ebp&lt;br /&gt;c012c3e3:       e8 fc ff ff ff          call   c012c3e4 &lt;no_blink+0x4&gt;&lt;br /&gt;                        c012c3e4: R_386_PC32    mcount&lt;br /&gt;        return 0;&lt;br /&gt;}&lt;br /&gt;c012c3e8:       5d                      pop    %ebp&lt;br /&gt;c012c3e9:       31 c0                   xor    %eax,%eax&lt;br /&gt;c012c3eb:       c3                      ret&lt;br /&gt;c012c3ec:       8d 74 26 00             lea    0x0(%esi),%esi&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-4877237226505221758?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-14T20:31:45.279+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Floating Point</title><link>http://weichong78.blogspot.com/2008/10/floating-point.html</link><author>noreply@blogger.com (Wei Chong Tan)</author><pubDate>Tue, 30 Sep 2008 18:36:11 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-13656592.post-940751207063362144</guid><description>Last night, out of boredom (because I had a swollen foot), I revised how floating point is represented in PC, using the IEEE Standard 754 format.  To convince myself about what was read, I code this short code snippet:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;/* This code is licensed under GPLv2 and above */&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main ()&lt;br /&gt;{&lt;br /&gt;/* Single Precision Float */&lt;br /&gt;/* S Exponent     Significant */&lt;br /&gt;/* 0 1000_0000 [1]000_0000_0000_0000_0000_0000 */&lt;br /&gt;/* Note that the Exponent is in Biased format, therefore, &lt;br /&gt;   1000_0000 - 0111_1111 (decimal 127) = 0000_0001 (decimal 2) &lt;br /&gt;   while the Significant is in Normalized format, which means the 1.bbbb is implied */&lt;br /&gt;/* 0100_0000_0000_0000_0000_0000_0000_0000 */&lt;br /&gt;/* Hex: 0x40000000 */&lt;br /&gt;&lt;br /&gt;    unsigned long int usi = 0x40000000;&lt;br /&gt;    signed long int si = usi;&lt;br /&gt;    float f = usi;&lt;br /&gt;&lt;br /&gt;    unsigned long int *uptr = &amp;usi;&lt;br /&gt;    signed long int *sptr = &amp;usi;&lt;br /&gt;    float *fptr = &amp;usi;&lt;br /&gt;&lt;br /&gt;    printf("for 0x40000000\n");&lt;br /&gt;    printf("before assignment:\n");&lt;br /&gt;    printf("unsigned int = %lu, signed int = %ld, float = %f\n", *uptr, *sptr, *fptr);&lt;br /&gt;    printf("after assignment:\n");&lt;br /&gt;    printf("unsigned int = %lu, signed int = %ld, float = %f\n", usi, si, f);&lt;br /&gt;&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;and the output from the execution is:&lt;br /&gt;&lt;div class="mycode"&gt;&lt;br /&gt;for 0x40000000&lt;br /&gt;before assignment:&lt;br /&gt;unsigned int = 1073741824, signed int = 1073741824, float = 2.000000&lt;br /&gt;after assignment:&lt;br /&gt;unsigned int = 1073741824, signed int = 1073741824, float = 1073741824.000000&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13656592-940751207063362144?l=weichong78.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-01T09:36:11.682+08:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item></channel></rss>

