rtas_flash.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  c 2001 PPC 64 Team, IBM Corp
  3.  *
  4.  *      This program is free software; you can redistribute it and/or
  5.  *      modify it under the terms of the GNU General Public License
  6.  *      as published by the Free Software Foundation; either version
  7.  *      2 of the License, or (at your option) any later version.
  8.  *
  9.  * /proc/ppc64/rtas/firmware_flash interface
  10.  *
  11.  * This file implements a firmware_flash interface to pump a firmware
  12.  * image into the kernel.  At reboot time rtas_restart() will see the
  13.  * firmware image and flash it as it reboots (see rtas.c).
  14.  */
  15. #include <linux/module.h>
  16. #include <linux/config.h>
  17. #include <linux/proc_fs.h>
  18. #include <linux/init.h>
  19. #include <asm/uaccess.h>
  20. #include <asm/rtas.h>
  21. #define MODULE_VERSION "1.0"
  22. #define MODULE_NAME "rtas_flash"
  23. #define FIRMWARE_FLASH_NAME "firmware_flash"
  24. /* Local copy of the flash block list.
  25.  * We only allow one open of the flash proc file and create this
  26.  * list as we go.  This list will be put in the kernel's
  27.  * rtas_firmware_flash_list global var once it is fully read.
  28.  *
  29.  * For convenience as we build the list we use virtual addrs,
  30.  * we do not fill in the version number, and the length field
  31.  * is treated as the number of entries currently in the block
  32.  * (i.e. not a byte count).  This is all fixed on release.
  33.  */
  34. static struct flash_block_list *flist;
  35. static char *flash_msg;
  36. static int flash_possible;
  37. static int rtas_flash_open(struct inode *inode, struct file *file)
  38. {
  39. if ((file->f_mode & FMODE_WRITE) && flash_possible) {
  40. if (flist)
  41. return -EBUSY;
  42. flist = (struct flash_block_list *)get_free_page(GFP_KERNEL);
  43. if (!flist)
  44. return -ENOMEM;
  45. }
  46. return 0;
  47. }
  48. /* Do simple sanity checks on the flash image. */
  49. static int flash_list_valid(struct flash_block_list *flist)
  50. {
  51. struct flash_block_list *f;
  52. int i;
  53. unsigned long block_size, image_size;
  54. flash_msg = NULL;
  55. /* Paranoid self test here.  We also collect the image size. */
  56. image_size = 0;
  57. for (f = flist; f; f = f->next) {
  58. for (i = 0; i < f->num_blocks; i++) {
  59. if (f->blocks[i].data == NULL) {
  60. flash_msg = "error: internal error null datan";
  61. return 0;
  62. }
  63. block_size = f->blocks[i].length;
  64. if (block_size <= 0 || block_size > PAGE_SIZE) {
  65. flash_msg = "error: internal error bad lengthn";
  66. return 0;
  67. }
  68. image_size += block_size;
  69. }
  70. }
  71. if (image_size < (256 << 10)) {
  72. if (image_size < 2)
  73. flash_msg = NULL; /* allow "clear" of image */
  74. else
  75. flash_msg = "error: flash image shortn";
  76. return 0;
  77. }
  78. printk(KERN_INFO "FLASH: flash image with %ld bytes stored for hardware flash on rebootn", image_size);
  79. return 1;
  80. }
  81. static void free_flash_list(struct flash_block_list *f)
  82. {
  83. struct flash_block_list *next;
  84. int i;
  85. while (f) {
  86. for (i = 0; i < f->num_blocks; i++)
  87. free_page((unsigned long)(f->blocks[i].data));
  88. next = f->next;
  89. free_page((unsigned long)f);
  90. f = next;
  91. }
  92. }
  93. static int rtas_flash_release(struct inode *inode, struct file *file)
  94. {
  95. if (flist) {
  96. /* Always clear saved list on a new attempt. */
  97. if (rtas_firmware_flash_list.next) {
  98. free_flash_list(rtas_firmware_flash_list.next);
  99. rtas_firmware_flash_list.next = NULL;
  100. }
  101. if (flash_list_valid(flist))
  102. rtas_firmware_flash_list.next = flist;
  103. else
  104. free_flash_list(flist);
  105. flist = NULL;
  106. }
  107. return 0;
  108. }
  109. /* Reading the proc file will show status (not the firmware contents) */
  110. static ssize_t rtas_flash_read(struct file *file, char *buf,
  111.        size_t count, loff_t *ppos)
  112. {
  113. int error;
  114. char *msg;
  115. int msglen;
  116. if (!flash_possible) {
  117. msg = "error: this partition does not have service authorityn";
  118. } else if (flist) {
  119. msg = "info: this file is busy for write by some processn";
  120. } else if (flash_msg) {
  121. msg = flash_msg; /* message from last flash attempt */
  122. } else if (rtas_firmware_flash_list.next) {
  123. msg = "ready: firmware image ready for flash on rebootn";
  124. } else {
  125. msg = "info: no firmware image for flashn";
  126. }
  127. msglen = strlen(msg);
  128. if (msglen > count)
  129. msglen = count;
  130. if (ppos && *ppos != 0)
  131. return 0; /* be cheap */
  132. error = verify_area(VERIFY_WRITE, buf, msglen);
  133. if (error)
  134. return -EINVAL;
  135. copy_to_user(buf, msg, msglen);
  136. if (ppos)
  137. *ppos = msglen;
  138. return msglen;
  139. }
  140. /* We could be much more efficient here.  But to keep this function
  141.  * simple we allocate a page to the block list no matter how small the
  142.  * count is.  If the system is low on memory it will be just as well
  143.  * that we fail....
  144.  */
  145. static ssize_t rtas_flash_write(struct file *file, const char *buffer,
  146. size_t count, loff_t *off)
  147. {
  148. size_t len = count;
  149. char *p;
  150. int next_free;
  151. struct flash_block_list *fl = flist;
  152. if (!flash_possible || len == 0)
  153. return len; /* discard data */
  154. while (fl->next)
  155. fl = fl->next; /* seek to last block_list for append */
  156. next_free = fl->num_blocks;
  157. if (next_free == FLASH_BLOCKS_PER_NODE) {
  158. /* Need to allocate another block_list */
  159. fl->next = (struct flash_block_list *)get_free_page(GFP_KERNEL);
  160. if (!fl->next)
  161. return -ENOMEM;
  162. fl = fl->next;
  163. next_free = 0;
  164. }
  165. if (len > PAGE_SIZE)
  166. len = PAGE_SIZE;
  167. p = (char *)get_free_page(GFP_KERNEL);
  168. if (!p)
  169. return -ENOMEM;
  170. if(copy_from_user(p, buffer, len)) {
  171. free_page((unsigned long)p);
  172. return -EFAULT;
  173. }
  174. fl->blocks[next_free].data = p;
  175. fl->blocks[next_free].length = len;
  176. fl->num_blocks++;
  177. return len;
  178. }
  179. static struct file_operations rtas_flash_operations = {
  180. read: rtas_flash_read,
  181. write: rtas_flash_write,
  182. open: rtas_flash_open,
  183. release: rtas_flash_release,
  184. };
  185. int __init rtas_flash_init(void)
  186. {
  187. struct proc_dir_entry *ent = NULL;
  188. if (!rtas_proc_dir) {
  189. printk(KERN_WARNING "rtas proc dir does not already exist");
  190. return -ENOENT;
  191. }
  192. if (rtas_token("ibm,update-flash-64-and-reboot") != RTAS_UNKNOWN_SERVICE)
  193. flash_possible = 1;
  194. if ((ent = create_proc_entry(FIRMWARE_FLASH_NAME, S_IRUSR | S_IWUSR, rtas_proc_dir)) != NULL) {
  195. ent->nlink = 1;
  196. ent->proc_fops = &rtas_flash_operations;
  197. ent->owner = THIS_MODULE;
  198. }
  199. return 0;
  200. }
  201. void __exit rtas_flash_cleanup(void)
  202. {
  203. if (!rtas_proc_dir)
  204. return;
  205. remove_proc_entry(FIRMWARE_FLASH_NAME, rtas_proc_dir);
  206. }
  207. module_init(rtas_flash_init);
  208. module_exit(rtas_flash_cleanup);
  209. MODULE_LICENSE("GPL");