Message ID | 7a4b8d6827503ae0e30745014504c72f0c5d6316.1662459668.git.baskov@ispras.ru |
---|---|
State | New |
Headers | show |
Series | x86_64: Improvements at compressed kernel stage | expand |
On Tue, 6 Sept 2022 at 12:42, Evgeniy Baskov <baskov@ispras.ru> wrote: > > To be able to extract kernel from EFI, console output functions > need to be replaceable by alternative implementations. > > Make all of those functions pointers. > Move serial console code to separate file. > What does kernel_add_identity_map() have to do with the above? Should that be a separate patch? > Signed-off-by: Evgeniy Baskov <baskov@ispras.ru> > --- > arch/x86/boot/compressed/Makefile | 2 +- > arch/x86/boot/compressed/ident_map_64.c | 15 ++- > arch/x86/boot/compressed/misc.c | 109 +-------------------- > arch/x86/boot/compressed/misc.h | 13 ++- > arch/x86/boot/compressed/putstr.c | 124 ++++++++++++++++++++++++ > 5 files changed, 146 insertions(+), 117 deletions(-) > create mode 100644 arch/x86/boot/compressed/putstr.c > > diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile > index 35ce1a64068b..29411864bfcd 100644 > --- a/arch/x86/boot/compressed/Makefile > +++ b/arch/x86/boot/compressed/Makefile > @@ -92,7 +92,7 @@ $(obj)/misc.o: $(obj)/../voffset.h > > vmlinux-objs-y := $(obj)/vmlinux.lds $(obj)/kernel_info.o $(obj)/head_$(BITS).o \ > $(obj)/misc.o $(obj)/string.o $(obj)/cmdline.o $(obj)/error.o \ > - $(obj)/piggy.o $(obj)/cpuflags.o > + $(obj)/piggy.o $(obj)/cpuflags.o $(obj)/putstr.o > > vmlinux-objs-$(CONFIG_EARLY_PRINTK) += $(obj)/early_serial_console.o > vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/kaslr.o > diff --git a/arch/x86/boot/compressed/ident_map_64.c b/arch/x86/boot/compressed/ident_map_64.c > index c20cd31e665f..c39373687e50 100644 > --- a/arch/x86/boot/compressed/ident_map_64.c > +++ b/arch/x86/boot/compressed/ident_map_64.c > @@ -89,12 +89,20 @@ phys_addr_t physical_mask = (1ULL << __PHYSICAL_MASK_SHIFT) - 1; > static struct x86_mapping_info mapping_info; > int has_nx; > > +/* > + * This points to actual implementation of mapping function. > + * Either the one down below or the UEFI API wrapper. > + */ > +unsigned long (*kernel_add_identity_map)(unsigned long start, > + unsigned long end, > + unsigned int flags); > + > /* > * Adds the specified range to the identity mappings. > */ > -unsigned long kernel_add_identity_map(unsigned long start, > - unsigned long end, > - unsigned int flags) > +unsigned long kernel_add_identity_map_(unsigned long start, > + unsigned long end, > + unsigned int flags) > { > int ret; > > @@ -136,6 +144,7 @@ void initialize_identity_maps(void *rmode) > struct setup_data *sd; > > boot_params = rmode; > + kernel_add_identity_map = kernel_add_identity_map_; > > /* Exclude the encryption mask from __PHYSICAL_MASK */ > physical_mask &= ~sme_me_mask; > diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c > index d377e434c4e3..e2c0d05ac293 100644 > --- a/arch/x86/boot/compressed/misc.c > +++ b/arch/x86/boot/compressed/misc.c > @@ -53,13 +53,6 @@ struct port_io_ops pio_ops; > memptr free_mem_ptr; > memptr free_mem_end_ptr; > > -static char *vidmem; > -static int vidport; > - > -/* These might be accessed before .bss is cleared, so use .data instead. */ > -static int lines __section(".data"); > -static int cols __section(".data"); > - > #ifdef CONFIG_KERNEL_GZIP > #include "../../../../lib/decompress_inflate.c" > #endif > @@ -92,95 +85,6 @@ static int cols __section(".data"); > * ../header.S. > */ > > -static void scroll(void) > -{ > - int i; > - > - memmove(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2); > - for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2) > - vidmem[i] = ' '; > -} > - > -#define XMTRDY 0x20 > - > -#define TXR 0 /* Transmit register (WRITE) */ > -#define LSR 5 /* Line Status */ > -static void serial_putchar(int ch) > -{ > - unsigned timeout = 0xffff; > - > - while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) > - cpu_relax(); > - > - outb(ch, early_serial_base + TXR); > -} > - > -void __putstr(const char *s) > -{ > - int x, y, pos; > - char c; > - > - if (early_serial_base) { > - const char *str = s; > - while (*str) { > - if (*str == '\n') > - serial_putchar('\r'); > - serial_putchar(*str++); > - } > - } > - > - if (lines == 0 || cols == 0) > - return; > - > - x = boot_params->screen_info.orig_x; > - y = boot_params->screen_info.orig_y; > - > - while ((c = *s++) != '\0') { > - if (c == '\n') { > - x = 0; > - if (++y >= lines) { > - scroll(); > - y--; > - } > - } else { > - vidmem[(x + cols * y) * 2] = c; > - if (++x >= cols) { > - x = 0; > - if (++y >= lines) { > - scroll(); > - y--; > - } > - } > - } > - } > - > - boot_params->screen_info.orig_x = x; > - boot_params->screen_info.orig_y = y; > - > - pos = (x + cols * y) * 2; /* Update cursor position */ > - outb(14, vidport); > - outb(0xff & (pos >> 9), vidport+1); > - outb(15, vidport); > - outb(0xff & (pos >> 1), vidport+1); > -} > - > -void __puthex(unsigned long value) > -{ > - char alpha[2] = "0"; > - int bits; > - > - for (bits = sizeof(value) * 8 - 4; bits >= 0; bits -= 4) { > - unsigned long digit = (value >> bits) & 0xf; > - > - if (digit < 0xA) > - alpha[0] = '0' + digit; > - else > - alpha[0] = 'a' + (digit - 0xA); > - > - __putstr(alpha); > - } > -} > - > #ifdef CONFIG_X86_NEED_RELOCS > static void handle_relocations(void *output, unsigned long output_len, > unsigned long virt_addr) > @@ -407,17 +311,6 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, > > sanitize_boot_params(boot_params); > > - if (boot_params->screen_info.orig_video_mode == 7) { > - vidmem = (char *) 0xb0000; > - vidport = 0x3b4; > - } else { > - vidmem = (char *) 0xb8000; > - vidport = 0x3d4; > - } > - > - lines = boot_params->screen_info.orig_video_lines; > - cols = boot_params->screen_info.orig_video_cols; > - > init_default_io_ops(); > > /* > @@ -428,7 +321,7 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, > */ > early_tdx_detect(); > > - console_init(); > + init_bare_console(); > > /* > * Save RSDP address for later use. Have this after console_init() > diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h > index a4f99516f310..39dc3de50268 100644 > --- a/arch/x86/boot/compressed/misc.h > +++ b/arch/x86/boot/compressed/misc.h > @@ -53,8 +53,8 @@ extern memptr free_mem_end_ptr; > void *malloc(int size); > void free(void *where); > extern struct boot_params *boot_params; > -void __putstr(const char *s); > -void __puthex(unsigned long value); > +extern void (*__putstr)(const char *s); > +extern void (*__puthex)(unsigned long value); > #define error_putstr(__x) __putstr(__x) > #define error_puthex(__x) __puthex(__x) > > @@ -124,6 +124,9 @@ static inline void console_init(void) > { } > #endif > > +/* putstr.c */ > +void init_bare_console(void); > + > #ifdef CONFIG_AMD_MEM_ENCRYPT > void sev_enable(struct boot_params *bp); > void sev_es_shutdown_ghcb(void); > @@ -172,9 +175,9 @@ static inline int count_immovable_mem_regions(void) { return 0; } > extern unsigned int __pgtable_l5_enabled, pgdir_shift, ptrs_per_p4d; > #endif > #ifdef CONFIG_X86_64 > -extern unsigned long kernel_add_identity_map(unsigned long start, > - unsigned long end, > - unsigned int flags); > +extern unsigned long (*kernel_add_identity_map)(unsigned long start, > + unsigned long end, > + unsigned int flags); > #else > static inline unsigned long kernel_add_identity_map(unsigned long start, > unsigned long end, > diff --git a/arch/x86/boot/compressed/putstr.c b/arch/x86/boot/compressed/putstr.c > new file mode 100644 > index 000000000000..accba0de8be9 > --- /dev/null > +++ b/arch/x86/boot/compressed/putstr.c > @@ -0,0 +1,124 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include "misc.h" > + > +/* These might be accessed before .bss is cleared, so use .data instead. */ > +static char *vidmem __section(".data"); > +static int vidport __section(".data"); > +static int lines __section(".data"); > +static int cols __section(".data"); > + > +void (*__putstr)(const char *s); > +void (*__puthex)(unsigned long value); > + > +static void putstr(const char *s); > +static void puthex(unsigned long value); > + > +void init_bare_console(void) > +{ > + __putstr = putstr; > + __puthex = puthex; > + > + if (boot_params->screen_info.orig_video_mode == 7) { > + vidmem = (char *) 0xb0000; > + vidport = 0x3b4; > + } else { > + vidmem = (char *) 0xb8000; > + vidport = 0x3d4; > + } > + > + lines = boot_params->screen_info.orig_video_lines; > + cols = boot_params->screen_info.orig_video_cols; > + > + console_init(); > +} > + > +static void scroll(void) > +{ > + int i; > + > + memmove(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2); > + for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2) > + vidmem[i] = ' '; > +} > + > +#define XMTRDY 0x20 > + > +#define TXR 0 /* Transmit register (WRITE) */ > +#define LSR 5 /* Line Status */ > + > +static void serial_putchar(int ch) > +{ > + unsigned int timeout = 0xffff; > + > + while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) > + cpu_relax(); > + > + outb(ch, early_serial_base + TXR); > +} > + > +static void putstr(const char *s) > +{ > + int x, y, pos; > + char c; > + > + if (early_serial_base) { > + const char *str = s; > + > + while (*str) { > + if (*str == '\n') > + serial_putchar('\r'); > + serial_putchar(*str++); > + } > + } > + > + if (lines == 0 || cols == 0) > + return; > + > + x = boot_params->screen_info.orig_x; > + y = boot_params->screen_info.orig_y; > + > + while ((c = *s++) != '\0') { > + if (c == '\n') { > + x = 0; > + if (++y >= lines) { > + scroll(); > + y--; > + } > + } else { > + vidmem[(x + cols * y) * 2] = c; > + if (++x >= cols) { > + x = 0; > + if (++y >= lines) { > + scroll(); > + y--; > + } > + } > + } > + } > + > + boot_params->screen_info.orig_x = x; > + boot_params->screen_info.orig_y = y; > + > + pos = (x + cols * y) * 2; /* Update cursor position */ > + outb(14, vidport); > + outb(0xff & (pos >> 9), vidport+1); > + outb(15, vidport); > + outb(0xff & (pos >> 1), vidport+1); > +} > + > +static void puthex(unsigned long value) > +{ > + char alpha[2] = "0"; > + int bits; > + > + for (bits = sizeof(value) * 8 - 4; bits >= 0; bits -= 4) { > + unsigned long digit = (value >> bits) & 0xf; > + > + if (digit < 0xA) > + alpha[0] = '0' + digit; > + else > + alpha[0] = 'a' + (digit - 0xA); > + > + putstr(alpha); > + } > +} > -- > 2.35.1 >
On 2022-10-19 10:23, Ard Biesheuvel wrote: > On Tue, 6 Sept 2022 at 12:42, Evgeniy Baskov <baskov@ispras.ru> wrote: >> >> To be able to extract kernel from EFI, console output functions >> need to be replaceable by alternative implementations. >> >> Make all of those functions pointers. >> Move serial console code to separate file. >> > > What does kernel_add_identity_map() have to do with the above? Should > that be a separate patch? It used to be dependent, but no longer is. I'll split making kernel_add_identity_map() a function pointer out into separate patch. > >> Signed-off-by: Evgeniy Baskov <baskov@ispras.ru> >> --- >> arch/x86/boot/compressed/Makefile | 2 +- >> arch/x86/boot/compressed/ident_map_64.c | 15 ++- >> arch/x86/boot/compressed/misc.c | 109 +-------------------- >> arch/x86/boot/compressed/misc.h | 13 ++- >> arch/x86/boot/compressed/putstr.c | 124 >> ++++++++++++++++++++++++ >> 5 files changed, 146 insertions(+), 117 deletions(-) >> create mode 100644 arch/x86/boot/compressed/putstr.c ...
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 35ce1a64068b..29411864bfcd 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -92,7 +92,7 @@ $(obj)/misc.o: $(obj)/../voffset.h vmlinux-objs-y := $(obj)/vmlinux.lds $(obj)/kernel_info.o $(obj)/head_$(BITS).o \ $(obj)/misc.o $(obj)/string.o $(obj)/cmdline.o $(obj)/error.o \ - $(obj)/piggy.o $(obj)/cpuflags.o + $(obj)/piggy.o $(obj)/cpuflags.o $(obj)/putstr.o vmlinux-objs-$(CONFIG_EARLY_PRINTK) += $(obj)/early_serial_console.o vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/kaslr.o diff --git a/arch/x86/boot/compressed/ident_map_64.c b/arch/x86/boot/compressed/ident_map_64.c index c20cd31e665f..c39373687e50 100644 --- a/arch/x86/boot/compressed/ident_map_64.c +++ b/arch/x86/boot/compressed/ident_map_64.c @@ -89,12 +89,20 @@ phys_addr_t physical_mask = (1ULL << __PHYSICAL_MASK_SHIFT) - 1; static struct x86_mapping_info mapping_info; int has_nx; +/* + * This points to actual implementation of mapping function. + * Either the one down below or the UEFI API wrapper. + */ +unsigned long (*kernel_add_identity_map)(unsigned long start, + unsigned long end, + unsigned int flags); + /* * Adds the specified range to the identity mappings. */ -unsigned long kernel_add_identity_map(unsigned long start, - unsigned long end, - unsigned int flags) +unsigned long kernel_add_identity_map_(unsigned long start, + unsigned long end, + unsigned int flags) { int ret; @@ -136,6 +144,7 @@ void initialize_identity_maps(void *rmode) struct setup_data *sd; boot_params = rmode; + kernel_add_identity_map = kernel_add_identity_map_; /* Exclude the encryption mask from __PHYSICAL_MASK */ physical_mask &= ~sme_me_mask; diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index d377e434c4e3..e2c0d05ac293 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -53,13 +53,6 @@ struct port_io_ops pio_ops; memptr free_mem_ptr; memptr free_mem_end_ptr; -static char *vidmem; -static int vidport; - -/* These might be accessed before .bss is cleared, so use .data instead. */ -static int lines __section(".data"); -static int cols __section(".data"); - #ifdef CONFIG_KERNEL_GZIP #include "../../../../lib/decompress_inflate.c" #endif @@ -92,95 +85,6 @@ static int cols __section(".data"); * ../header.S. */ -static void scroll(void) -{ - int i; - - memmove(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2); - for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2) - vidmem[i] = ' '; -} - -#define XMTRDY 0x20 - -#define TXR 0 /* Transmit register (WRITE) */ -#define LSR 5 /* Line Status */ -static void serial_putchar(int ch) -{ - unsigned timeout = 0xffff; - - while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) - cpu_relax(); - - outb(ch, early_serial_base + TXR); -} - -void __putstr(const char *s) -{ - int x, y, pos; - char c; - - if (early_serial_base) { - const char *str = s; - while (*str) { - if (*str == '\n') - serial_putchar('\r'); - serial_putchar(*str++); - } - } - - if (lines == 0 || cols == 0) - return; - - x = boot_params->screen_info.orig_x; - y = boot_params->screen_info.orig_y; - - while ((c = *s++) != '\0') { - if (c == '\n') { - x = 0; - if (++y >= lines) { - scroll(); - y--; - } - } else { - vidmem[(x + cols * y) * 2] = c; - if (++x >= cols) { - x = 0; - if (++y >= lines) { - scroll(); - y--; - } - } - } - } - - boot_params->screen_info.orig_x = x; - boot_params->screen_info.orig_y = y; - - pos = (x + cols * y) * 2; /* Update cursor position */ - outb(14, vidport); - outb(0xff & (pos >> 9), vidport+1); - outb(15, vidport); - outb(0xff & (pos >> 1), vidport+1); -} - -void __puthex(unsigned long value) -{ - char alpha[2] = "0"; - int bits; - - for (bits = sizeof(value) * 8 - 4; bits >= 0; bits -= 4) { - unsigned long digit = (value >> bits) & 0xf; - - if (digit < 0xA) - alpha[0] = '0' + digit; - else - alpha[0] = 'a' + (digit - 0xA); - - __putstr(alpha); - } -} - #ifdef CONFIG_X86_NEED_RELOCS static void handle_relocations(void *output, unsigned long output_len, unsigned long virt_addr) @@ -407,17 +311,6 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, sanitize_boot_params(boot_params); - if (boot_params->screen_info.orig_video_mode == 7) { - vidmem = (char *) 0xb0000; - vidport = 0x3b4; - } else { - vidmem = (char *) 0xb8000; - vidport = 0x3d4; - } - - lines = boot_params->screen_info.orig_video_lines; - cols = boot_params->screen_info.orig_video_cols; - init_default_io_ops(); /* @@ -428,7 +321,7 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, */ early_tdx_detect(); - console_init(); + init_bare_console(); /* * Save RSDP address for later use. Have this after console_init() diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index a4f99516f310..39dc3de50268 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h @@ -53,8 +53,8 @@ extern memptr free_mem_end_ptr; void *malloc(int size); void free(void *where); extern struct boot_params *boot_params; -void __putstr(const char *s); -void __puthex(unsigned long value); +extern void (*__putstr)(const char *s); +extern void (*__puthex)(unsigned long value); #define error_putstr(__x) __putstr(__x) #define error_puthex(__x) __puthex(__x) @@ -124,6 +124,9 @@ static inline void console_init(void) { } #endif +/* putstr.c */ +void init_bare_console(void); + #ifdef CONFIG_AMD_MEM_ENCRYPT void sev_enable(struct boot_params *bp); void sev_es_shutdown_ghcb(void); @@ -172,9 +175,9 @@ static inline int count_immovable_mem_regions(void) { return 0; } extern unsigned int __pgtable_l5_enabled, pgdir_shift, ptrs_per_p4d; #endif #ifdef CONFIG_X86_64 -extern unsigned long kernel_add_identity_map(unsigned long start, - unsigned long end, - unsigned int flags); +extern unsigned long (*kernel_add_identity_map)(unsigned long start, + unsigned long end, + unsigned int flags); #else static inline unsigned long kernel_add_identity_map(unsigned long start, unsigned long end, diff --git a/arch/x86/boot/compressed/putstr.c b/arch/x86/boot/compressed/putstr.c new file mode 100644 index 000000000000..accba0de8be9 --- /dev/null +++ b/arch/x86/boot/compressed/putstr.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "misc.h" + +/* These might be accessed before .bss is cleared, so use .data instead. */ +static char *vidmem __section(".data"); +static int vidport __section(".data"); +static int lines __section(".data"); +static int cols __section(".data"); + +void (*__putstr)(const char *s); +void (*__puthex)(unsigned long value); + +static void putstr(const char *s); +static void puthex(unsigned long value); + +void init_bare_console(void) +{ + __putstr = putstr; + __puthex = puthex; + + if (boot_params->screen_info.orig_video_mode == 7) { + vidmem = (char *) 0xb0000; + vidport = 0x3b4; + } else { + vidmem = (char *) 0xb8000; + vidport = 0x3d4; + } + + lines = boot_params->screen_info.orig_video_lines; + cols = boot_params->screen_info.orig_video_cols; + + console_init(); +} + +static void scroll(void) +{ + int i; + + memmove(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2); + for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2) + vidmem[i] = ' '; +} + +#define XMTRDY 0x20 + +#define TXR 0 /* Transmit register (WRITE) */ +#define LSR 5 /* Line Status */ + +static void serial_putchar(int ch) +{ + unsigned int timeout = 0xffff; + + while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) + cpu_relax(); + + outb(ch, early_serial_base + TXR); +} + +static void putstr(const char *s) +{ + int x, y, pos; + char c; + + if (early_serial_base) { + const char *str = s; + + while (*str) { + if (*str == '\n') + serial_putchar('\r'); + serial_putchar(*str++); + } + } + + if (lines == 0 || cols == 0) + return; + + x = boot_params->screen_info.orig_x; + y = boot_params->screen_info.orig_y; + + while ((c = *s++) != '\0') { + if (c == '\n') { + x = 0; + if (++y >= lines) { + scroll(); + y--; + } + } else { + vidmem[(x + cols * y) * 2] = c; + if (++x >= cols) { + x = 0; + if (++y >= lines) { + scroll(); + y--; + } + } + } + } + + boot_params->screen_info.orig_x = x; + boot_params->screen_info.orig_y = y; + + pos = (x + cols * y) * 2; /* Update cursor position */ + outb(14, vidport); + outb(0xff & (pos >> 9), vidport+1); + outb(15, vidport); + outb(0xff & (pos >> 1), vidport+1); +} + +static void puthex(unsigned long value) +{ + char alpha[2] = "0"; + int bits; + + for (bits = sizeof(value) * 8 - 4; bits >= 0; bits -= 4) { + unsigned long digit = (value >> bits) & 0xf; + + if (digit < 0xA) + alpha[0] = '0' + digit; + else + alpha[0] = 'a' + (digit - 0xA); + + putstr(alpha); + } +}
To be able to extract kernel from EFI, console output functions need to be replaceable by alternative implementations. Make all of those functions pointers. Move serial console code to separate file. Signed-off-by: Evgeniy Baskov <baskov@ispras.ru> --- arch/x86/boot/compressed/Makefile | 2 +- arch/x86/boot/compressed/ident_map_64.c | 15 ++- arch/x86/boot/compressed/misc.c | 109 +-------------------- arch/x86/boot/compressed/misc.h | 13 ++- arch/x86/boot/compressed/putstr.c | 124 ++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 117 deletions(-) create mode 100644 arch/x86/boot/compressed/putstr.c