x86/efi: earlyprintk=efi,keep fix

earlyprintk=efi,keep will cause kernel hangs while freeing initmem like
below:

VFS: Mounted root (ext4 filesystem) readonly on device 254:2.
devtmpfs: mounted
Freeing unused kernel memory: 880K (ffffffff817d4000 - ffffffff818b0000)

It is caused by efi earlyprintk use __init function which will be freed
later. Such as early_efi_write is marked as __init, also it will use
early_ioremap which is init function as well.

To fix this issue, I added early initcall early_efi_map_fb which maps
the whole efi fb for later use. OTOH, adding a wrapper function
early_efi_map which calls early_ioremap before ioremap is available.

With this patch applied efi boot ok with earlyprintk=efi,keep console=efi

Signed-off-by: Dave Young <dyoung@redhat.com>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>

authored by Dave Young and committed by Matt Fleming 34f51147 47514c99

Changed files
+64 -19
arch
x86
platform
+64 -19
arch/x86/platform/efi/early_printk.c
··· 14 14 15 15 static const struct font_desc *font; 16 16 static u32 efi_x, efi_y; 17 + static void *efi_fb; 18 + static bool early_efi_keep; 17 19 18 - static __init void early_efi_clear_scanline(unsigned int y) 20 + /* 21 + * efi earlyprintk need use early_ioremap to map the framebuffer. 22 + * But early_ioremap is not usable for earlyprintk=efi,keep, ioremap should 23 + * be used instead. ioremap will be available after paging_init() which is 24 + * earlier than initcall callbacks. Thus adding this early initcall function 25 + * early_efi_map_fb to map the whole efi framebuffer. 26 + */ 27 + static __init int early_efi_map_fb(void) 19 28 { 20 - unsigned long base, *dst; 21 - u16 len; 29 + unsigned long base, size; 30 + 31 + if (!early_efi_keep) 32 + return 0; 22 33 23 34 base = boot_params.screen_info.lfb_base; 24 - len = boot_params.screen_info.lfb_linelength; 35 + size = boot_params.screen_info.lfb_size; 36 + efi_fb = ioremap(base, size); 25 37 26 - dst = early_ioremap(base + y*len, len); 38 + return efi_fb ? 0 : -ENOMEM; 39 + } 40 + early_initcall(early_efi_map_fb); 41 + 42 + /* 43 + * early_efi_map maps efi framebuffer region [start, start + len -1] 44 + * In case earlyprintk=efi,keep we have the whole framebuffer mapped already 45 + * so just return the offset efi_fb + start. 46 + */ 47 + static __init_refok void *early_efi_map(unsigned long start, unsigned long len) 48 + { 49 + unsigned long base; 50 + 51 + base = boot_params.screen_info.lfb_base; 52 + 53 + if (efi_fb) 54 + return (efi_fb + start); 55 + else 56 + return early_ioremap(base + start, len); 57 + } 58 + 59 + static __init_refok void early_efi_unmap(void *addr, unsigned long len) 60 + { 61 + if (!efi_fb) 62 + early_iounmap(addr, len); 63 + } 64 + 65 + static void early_efi_clear_scanline(unsigned int y) 66 + { 67 + unsigned long *dst; 68 + u16 len; 69 + 70 + len = boot_params.screen_info.lfb_linelength; 71 + dst = early_efi_map(y*len, len); 27 72 if (!dst) 28 73 return; 29 74 30 75 memset(dst, 0, len); 31 - early_iounmap(dst, len); 76 + early_efi_unmap(dst, len); 32 77 } 33 78 34 - static __init void early_efi_scroll_up(void) 79 + static void early_efi_scroll_up(void) 35 80 { 36 - unsigned long base, *dst, *src; 81 + unsigned long *dst, *src; 37 82 u16 len; 38 83 u32 i, height; 39 84 40 - base = boot_params.screen_info.lfb_base; 41 85 len = boot_params.screen_info.lfb_linelength; 42 86 height = boot_params.screen_info.lfb_height; 43 87 44 88 for (i = 0; i < height - font->height; i++) { 45 - dst = early_ioremap(base + i*len, len); 89 + dst = early_efi_map(i*len, len); 46 90 if (!dst) 47 91 return; 48 92 49 - src = early_ioremap(base + (i + font->height) * len, len); 93 + src = early_efi_map((i + font->height) * len, len); 50 94 if (!src) { 51 - early_iounmap(dst, len); 95 + early_efi_unmap(dst, len); 52 96 return; 53 97 } 54 98 55 99 memmove(dst, src, len); 56 100 57 - early_iounmap(src, len); 58 - early_iounmap(dst, len); 101 + early_efi_unmap(src, len); 102 + early_efi_unmap(dst, len); 59 103 } 60 104 } 61 105 ··· 123 79 } 124 80 } 125 81 126 - static __init void 82 + static void 127 83 early_efi_write(struct console *con, const char *str, unsigned int num) 128 84 { 129 85 struct screen_info *si; 130 - unsigned long base; 131 86 unsigned int len; 132 87 const char *s; 133 88 void *dst; 134 89 135 - base = boot_params.screen_info.lfb_base; 136 90 si = &boot_params.screen_info; 137 91 len = si->lfb_linelength; 138 92 ··· 151 109 for (h = 0; h < font->height; h++) { 152 110 unsigned int n, x; 153 111 154 - dst = early_ioremap(base + (efi_y + h) * len, len); 112 + dst = early_efi_map((efi_y + h) * len, len); 155 113 if (!dst) 156 114 return; 157 115 ··· 165 123 s++; 166 124 } 167 125 168 - early_iounmap(dst, len); 126 + early_efi_unmap(dst, len); 169 127 } 170 128 171 129 num -= count; ··· 221 179 for (i = 0; i < (yres - efi_y) / font->height; i++) 222 180 early_efi_scroll_up(); 223 181 182 + /* early_console_register will unset CON_BOOT in case ,keep */ 183 + if (!(con->flags & CON_BOOT)) 184 + early_efi_keep = true; 224 185 return 0; 225 186 } 226 187