parisc: sticon - fix 64bit and font selection
Subsystems (3)
Helge Deller
maintainerPATCH 1/1 parisc: sticon - fix 64bit and font selection
STI text console (sticon) was broken on 64bit machines with more than 4GB and lead in some cases to a kernel crash.
Since sticon uses the 32bit STI API it needs to keep pointers to memory below 4GB. But on a 64bit kernel some memory regions (e.g. the kernel stack) might be above 4GB which then may crash the kernel in the STI functions.
Additionally sticon didn't selected the built-in framebuffer fonts by default. This is now fixed.
On a side-note: Theoretically we could enhance the sticon driver to use the 64bit STI API. But this just adds complexity and on some machines a 64bit STI is just not available.
drivers/video/console/sticore.c +103 -63
@@ -3,7 +3,7 @@* core code for console driver using HP's STI firmware * * Copyright (C) 2000 Philipp Rumpf <[email protected]> -* Copyright (C) 2001-2003 Helge Deller <[email protected]> +* Copyright (C) 2001-2013 Helge Deller <[email protected]> * Copyright (C) 2001-2002 Thomas Bogendoerfer <[email protected]> * * TODO:
@@ -30,7 +30,7 @@#include "../sticore.h" -#define STI_DRIVERVERSION "Version 0.9a" +#define STI_DRIVERVERSION "Version 0.9b"static struct sti_struct *default_sti__read_mostly ;
@@ -73,28 +73,34 @@ static const struct sti_init_flags default_init_flags = {static int sti_init_graph (struct sti_struct *sti) { -struct sti_init_inptr_ext inptr_ext = {0 , }; -struct sti_init_inptr inptr = { - .text_planes =3 ,/* # of text planes (max 3 for STI) */ - .ext_ptr =STI_PTR (&inptr_ext) - }; -struct sti_init_outptr outptr = {0 , }; +struct sti_init_inptr *inptr = &sti->sti_data->init_inptr; +struct sti_init_inptr_ext *inptr_ext = &sti->sti_data->init_inptr_ext; +struct sti_init_outptr *outptr = &sti->sti_data->init_outptr;unsigned long flags; -int ret; +int ret, err;spin_lock_irqsave (&sti->lock, flags); - ret =STI_CALL (sti->init_graph, &default_init_flags, &inptr, - &outptr, sti->glob_cfg); +memset (inptr,0 ,sizeof (*inptr)); + inptr->text_planes =3 ;/* # of text planes (max 3 for STI) */ +memset (inptr_ext,0 ,sizeof (*inptr_ext)); + inptr->ext_ptr =STI_PTR (inptr_ext); + outptr->errno =0 ; + + ret =sti_call (sti, sti->init_graph, &default_init_flags, inptr, + outptr, sti->glob_cfg); + +if (ret >=0 ) + sti->text_planes = outptr->text_planes; + err = outptr->errno;spin_unlock_irqrestore (&sti->lock, flags);if (ret <0 ) { -printk (KERN_ERR "STI init_graph failed (ret %d, errno %d)\n" ,ret,outptr.errno); +pr_err ("STI init_graph failed (ret %d, errno %d)\n" , ret, err);return -1 ; } - sti->text_planes = outptr.text_planes;return 0 ; }
@@ -104,16 +110,18 @@ static const struct sti_conf_flags default_conf_flags = {static void sti_inq_conf (struct sti_struct *sti) { -struct sti_conf_inptr inptr = {0 , }; +struct sti_conf_inptr *inptr = &sti->sti_data->inq_inptr; +struct sti_conf_outptr *outptr = &sti->sti_data->inq_outptr;unsigned long flags;s32 ret; - sti->outptr.ext_ptr =STI_PTR (&sti->outptr_ext); + outptr->ext_ptr =STI_PTR (&sti->sti_data->inq_outptr_ext);do {spin_lock_irqsave (&sti->lock, flags); - ret =STI_CALL (sti->inq_conf, &default_conf_flags, - &inptr, &sti->outptr, sti->glob_cfg); +memset (inptr,0 ,sizeof (*inptr)); + ret =sti_call (sti, sti->inq_conf, &default_conf_flags, + inptr, outptr, sti->glob_cfg);spin_unlock_irqrestore (&sti->lock, flags); }while (ret ==1 ); }
@@ -126,7 +134,8 @@ static const struct sti_font_flags default_font_flags = {void sti_putc (struct sti_struct *sti,int c,int y,int x) { -struct sti_font_inptr inptr = { +struct sti_font_inptr *inptr = &sti->sti_data->font_inptr; +struct sti_font_inptr inptr_default = { .font_start_addr=STI_PTR (sti->font->raw), .index =c_index (sti, c), .fg_color =c_fg (sti, c),
@@ -134,14 +143,15 @@ sti_putc(struct sti_struct *sti, int c, int y, int x) .dest_x = x * sti->font_width, .dest_y = y * sti->font_height, }; -struct sti_font_outptr outptr = {0 , }; +struct sti_font_outptr *outptr = &sti->sti_data->font_outptr;s32 ret;unsigned long flags;do {spin_lock_irqsave (&sti->lock, flags); - ret =STI_CALL (sti->font_unpmv, &default_font_flags, - &inptr, &outptr, sti->glob_cfg); + *inptr = inptr_default; + ret =sti_call (sti, sti->font_unpmv, &default_font_flags, + inptr, outptr, sti->glob_cfg);spin_unlock_irqrestore (&sti->lock, flags); }while (ret ==1 ); }
@@ -156,7 +166,8 @@ void sti_set(struct sti_struct *sti, int src_y, int src_x, int height, int width, u8 color) { - struct sti_blkmv_inptr inptr = { + struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr; + struct sti_blkmv_inptr inptr_default = { .fg_color = color, .bg_color = color, .src_x = src_x,
@@ -166,14 +177,15 @@ sti_set(struct sti_struct *sti, int src_y, int src_x, .width = width, .height = height, }; -struct sti_blkmv_outptr outptr = {0 , }; +struct sti_blkmv_outptr *outptr = &sti->sti_data->blkmv_outptr;s32 ret;unsigned long flags;do {spin_lock_irqsave (&sti->lock, flags); - ret =STI_CALL (sti->block_move, &clear_blkmv_flags, - &inptr, &outptr, sti->glob_cfg); + *inptr = inptr_default; + ret =sti_call (sti, sti->block_move, &clear_blkmv_flags, + inptr, outptr, sti->glob_cfg);spin_unlock_irqrestore (&sti->lock, flags); }while (ret ==1 ); }
@@ -182,7 +194,8 @@ void sti_clear(struct sti_struct *sti, int src_y, int src_x, int height, int width, int c) { - struct sti_blkmv_inptr inptr = { + struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr; + struct sti_blkmv_inptr inptr_default = { .fg_color = c_fg(sti, c), .bg_color = c_bg(sti, c), .src_x = src_x * sti->font_width,
@@ -192,14 +205,15 @@ sti_clear(struct sti_struct *sti, int src_y, int src_x, .width = width * sti->font_width, .height = height* sti->font_height, }; -struct sti_blkmv_outptr outptr = {0 , }; +struct sti_blkmv_outptr *outptr = &sti->sti_data->blkmv_outptr;s32 ret;unsigned long flags;do {spin_lock_irqsave (&sti->lock, flags); - ret =STI_CALL (sti->block_move, &clear_blkmv_flags, - &inptr, &outptr, sti->glob_cfg); + *inptr = inptr_default; + ret =sti_call (sti, sti->block_move, &clear_blkmv_flags, + inptr, outptr, sti->glob_cfg);spin_unlock_irqrestore (&sti->lock, flags); }while (ret ==1 ); }
@@ -212,7 +226,8 @@ void sti_bmove(struct sti_struct *sti, int src_y, int src_x, int dst_y, int dst_x, int height, int width) { - struct sti_blkmv_inptr inptr = { + struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr; + struct sti_blkmv_inptr inptr_default = { .src_x = src_x * sti->font_width, .src_y = src_y * sti->font_height, .dest_x = dst_x * sti->font_width,
@@ -220,14 +235,15 @@ sti_bmove(struct sti_struct *sti, int src_y, int src_x, .width = width * sti->font_width, .height = height* sti->font_height, }; -struct sti_blkmv_outptr outptr = {0 , }; +struct sti_blkmv_outptr *outptr = &sti->sti_data->blkmv_outptr;s32 ret;unsigned long flags;do {spin_lock_irqsave (&sti->lock, flags); - ret =STI_CALL (sti->block_move, &default_blkmv_flags, - &inptr, &outptr, sti->glob_cfg); + *inptr = inptr_default; + ret =sti_call (sti, sti->block_move, &default_blkmv_flags, + inptr, outptr, sti->glob_cfg);spin_unlock_irqrestore (&sti->lock, flags); }while (ret ==1 ); }
@@ -284,7 +300,7 @@ __setup("sti=", sti_setup); -static char *font_name[MAX_STI_ROMS ] = {"VGA8x16" , }; +static char *font_name[MAX_STI_ROMS ];static int font_index[MAX_STI_ROMS ], font_height[MAX_STI_ROMS ], font_width[MAX_STI_ROMS ];
@@ -389,10 +405,10 @@ static void sti_dump_outptr(struct sti_struct *sti)"%d used bits\n" "%d planes\n" "attributes %08x\n" , - sti->outptr.bits_per_pixel, - sti->outptr.bits_used, - sti->outptr.planes, - sti->outptr.attributes)); + sti->sti_data->inq_outptr.bits_per_pixel, + sti->sti_data->inq_outptr.bits_used, + sti->sti_data->inq_outptr.planes, + sti->sti_data->inq_outptr.attributes)); } static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address,
@@ -402,24 +418,21 @@ static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address,struct sti_glob_cfg_ext *glob_cfg_ext;void *save_addr;void *sti_mem_addr; -const int save_addr_size =1024 ;/* XXX */ -int i; +int i, size; -if (!sti->sti_mem_request) +if (sti->sti_mem_request <256 ) sti->sti_mem_request =256 ;/* STI default */ - glob_cfg =kzalloc (sizeof (*sti->glob_cfg),GFP_KERNEL ); - glob_cfg_ext =kzalloc (sizeof (*glob_cfg_ext),GFP_KERNEL ); - save_addr =kzalloc (save_addr_size,GFP_KERNEL ); - sti_mem_addr =kzalloc (sti->sti_mem_request,GFP_KERNEL ); + size =sizeof (struct sti_all_data ) + sti->sti_mem_request -256 ; -if (!(glob_cfg && glob_cfg_ext && save_addr && sti_mem_addr)) { -kfree (glob_cfg); -kfree (glob_cfg_ext); -kfree (save_addr); -kfree (sti_mem_addr); + sti->sti_data =kzalloc (size,STI_LOWMEM ); +if (!sti->sti_data)return -ENOMEM ; - } + + glob_cfg = &sti->sti_data->glob_cfg; + glob_cfg_ext = &sti->sti_data->glob_cfg_ext; + save_addr = &sti->sti_data->save_addr; + sti_mem_addr = &sti->sti_data->sti_mem_addr; glob_cfg->ext_ptr =STI_PTR (glob_cfg_ext); glob_cfg->save_addr =STI_PTR (save_addr);
@@ -475,32 +488,31 @@ static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address,return 0 ; } -#ifdef CONFIG_FB +#ifdef CONFIG_FONTS static struct sti_cooked_font *sti_select_fbfont (struct sti_cooked_rom *cooked_rom,const char *fbfont_name) { -const struct font_desc *fbfont; +const struct font_desc *fbfont =NULL ;unsigned int size, bpc;void *dest;struct sti_rom_font *nf;struct sti_cooked_font *cooked_font; -if (!fbfont_name || !strlen (fbfont_name)) -return NULL ; - fbfont =find_font (fbfont_name); +if (fbfont_name &&strlen (fbfont_name)) + fbfont =find_font (fbfont_name);if (!fbfont) fbfont =get_default_font (1024 ,768 , ~(u32 )0 , ~(u32 )0 );if (!fbfont)return NULL ; -DPRINTK ((KERN_DEBUG "selected %dx%d fb-font %s\n" , - fbfont->width, fbfont->height, fbfont->name)); +pr_info ("STI selected %dx%d framebuffer font %s for sticon\n" , + fbfont->width, fbfont->height, fbfont->name); bpc = ((fbfont->width+7 )/8 ) * fbfont->height; size = bpc *256 ; size +=sizeof (struct sti_rom_font ); - nf =kzalloc (size,GFP_KERNEL ); + nf =kzalloc (size,STI_LOWMEM );if (!nf)return NULL ;
@@ -637,7 +649,7 @@ static void *sti_bmode_font_raw(struct sti_cooked_font *f)unsigned char *n, *p, *q;int size = f->raw->bytes_per_char*256 +sizeof (struct sti_rom_font ); - n =kzalloc (4 *size,GFP_KERNEL ); + n =kzalloc (4 *size,STI_LOWMEM );if (!n)return NULL ; p = n +3 ;
@@ -673,7 +685,7 @@ static struct sti_rom *sti_get_bmode_rom (unsigned long address)sti_bmode_rom_copy (address +BMODE_LAST_ADDR_OFFS ,sizeof (size), &size); size = (size+3 ) /4 ; - raw =kmalloc (size,GFP_KERNEL ); + raw =kmalloc (size,STI_LOWMEM );if (raw) {sti_bmode_rom_copy (address, size, raw);memmove (&raw->res004, &raw->type[0 ],0x3c );
@@ -707,7 +719,7 @@ static struct sti_rom *sti_get_wmode_rom(unsigned long address)/* read the ROM size directly from the struct in ROM */ size =gsc_readl (address + offsetof(struct sti_rom ,last_addr)); - raw =kmalloc (size,GFP_KERNEL ); + raw =kmalloc (size,STI_LOWMEM );if (raw)sti_rom_copy (address, size, raw);
@@ -743,6 +755,10 @@ static int sti_read_rom(int wordmode, struct sti_struct *sti, address = (unsigned long )STI_PTR (raw); +pr_info ("STI ROM supports 32 %sbit firmware functions.\n" , + raw->alt_code_type ==ALT_CODE_TYPE_PA_RISC_64 + ?"and 64 " :"" ); + sti->font_unpmv = address + (raw->font_unpmv &0x03ffffff ); sti->block_move = address + (raw->block_move &0x03ffffff ); sti->init_graph = address + (raw->init_graph &0x03ffffff );
@@ -901,7 +917,8 @@ test_rom:sti_dump_globcfg (sti->glob_cfg, sti->sti_mem_request);sti_dump_outptr (sti); -printk (KERN_INFO " graphics card name: %s\n" , sti->outptr.dev_name ); +pr_info (" graphics card name: %s\n" , + sti->sti_data->inq_outptr.dev_name); sti_roms[num_sti_roms] = sti; num_sti_roms++;
@@ -1073,6 +1090,29 @@ struct sti_struct * sti_get_rom(unsigned int index) }EXPORT_SYMBOL (sti_get_rom); + +int sti_call (const struct sti_struct *sti,unsigned long func, +const void *flags,void *inptr,void *outptr, +struct sti_glob_cfg *glob_cfg) +{ +unsigned long _flags =STI_PTR (flags); +unsigned long _inptr =STI_PTR (inptr); +unsigned long _outptr =STI_PTR (outptr); +unsigned long _glob_cfg =STI_PTR (glob_cfg); +int ret; + +#ifdef CONFIG_64BIT +/* Check for overflow when using 32bit STI on 64bit kernel. */ +if (WARN_ONCE (_flags>>32 || _inptr>>32 || _outptr>>32 || _glob_cfg>>32 , +"Out of 32bit-range pointers!" )) +return -1 ; +#endif + + ret =pdc_sti_call (func, _flags, _inptr, _outptr, _glob_cfg); + +return ret; +} +MODULE_AUTHOR ("Philipp Rumpf, Helge Deller, Thomas Bogendoerfer" );MODULE_DESCRIPTION ("Core STI driver for HP's NGLE series graphics cards in HP PARISC machines" );MODULE_LICENSE ("GPL v2" );
drivers/video/sticore.h +50 -12
105 lines not on this page · raw message
Helge Deller
maintainerRe: [PATCH] parisc: sticon - fix 64bit and font selection (unfinished support-for-64bit-STI-API patch)
* Helge Deller <[email protected]>:
Quoted 8 lines
STI text console (sticon) was broken on 64bit machines with more than 4GB and lead in some cases to a kernel crash.
Since sticon uses the 32bit STI API it needs to keep pointers to memory below 4GB. But on a 64bit kernel some memory regions (e.g. the kernel stack) might be above 4GB which then may crash the kernel in the STI functions.
Quoted 6 lines
Additionally sticon didn't selected the built-in framebuffer fonts by default. This is now fixed.
On a side-note: Theoretically we could enhance the sticon driver to use the 64bit STI API. But this just adds complexity and on some machines a 64bit STI is just not available.
Just for the archive - here is an unfinished version of my STIcon patch which can be used to develop a version which additionally supports the 64bit STI functions.
Most changes are identical to the committed version.
arch/parisc/include/asm/pdc.h +6 -1
@@ -318,9 +318,14 @@ int pdc_iodc_getc(void);int pdc_iodc_print (const unsigned char *str,unsigned count);void pdc_emergency_unlock (void ); -int pdc_sti_call (unsigned long func,unsigned long flags, +int pdc_sti_call32 (unsigned long func,unsigned long flags,unsigned long inptr,unsigned long outputr,unsigned long glob_cfg); +#ifdef CONFIG_64BIT +int pdc_sti_call64 (unsigned long func,unsigned long flags, +unsigned long inptr,unsigned long outputr, +unsigned long glob_cfg); +#endif static inline char *os_id_to_string (u16 os_id) {switch (os_id) {
arch/parisc/kernel/firmware.c +18 -2
@@ -1185,7 +1185,7 @@ int pdc_iodc_getc(void)return ch; } -int pdc_sti_call (unsigned long func,unsigned long flags, +int pdc_sti_call32 (unsigned long func,unsigned long flags,unsigned long inptr,unsigned long outputr,unsigned long glob_cfg) {
@@ -1198,9 +1198,25 @@ int pdc_sti_call(unsigned long func, unsigned long flags,return retval; } -EXPORT_SYMBOL (pdc_sti_call); +EXPORT_SYMBOL (pdc_sti_call32);#ifdef CONFIG_64BIT +int pdc_sti_call64 (unsigned long func,unsigned long flags, +unsigned long inptr,unsigned long outputr, +unsigned long glob_cfg) +{ +int retval; +unsigned long irqflags; + +spin_lock_irqsave (&pdc_lock, irqflags); + retval =real64_call (func, flags, inptr, outputr, glob_cfg); +spin_unlock_irqrestore (&pdc_lock, irqflags); + +return retval; +} +EXPORT_SYMBOL (pdc_sti_call64); + +/** * pdc_pat_cell_get_number - Returns the cell number. * @cell_info: The return buffer.
drivers/video/console/sticore.c +132 -53
346 lines not on this page · raw message
drivers/video/sticore.h +87 -42
272 lines not on this page · raw message