Skip to content

Commit

Permalink
parisc: sticon - unbreak on 64bit kernel
Browse files Browse the repository at this point in the history
STI text console (sticon) was broken on 64bit machines with more than
4GB RAM and this 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 - beside the fact that some machines don't
provide a 64bit STI ROM - this would just add complexity.

Signed-off-by: Helge Deller <[email protected]>
Cc: [email protected] # 3.8+
  • Loading branch information
hdeller committed Nov 7, 2013
1 parent 1f2048f commit 0219132
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 80 deletions.
166 changes: 103 additions & 63 deletions drivers/video/console/sticore.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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;

Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
}
Expand All @@ -126,22 +134,24 @@ 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),
.bg_color = c_bg(sti, c),
.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);
}
Expand All @@ -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,
Expand All @@ -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);
}
Expand All @@ -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,
Expand All @@ -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);
}
Expand All @@ -212,22 +226,24 @@ 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,
.dest_y = dst_y * sti->font_height,
.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);
}
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -901,7 +917,8 @@ static struct sti_struct *sti_try_rom_generic(unsigned long address,
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++;
Expand Down Expand Up @@ -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");
Expand Down
Loading

0 comments on commit 0219132

Please sign in to comment.