From fbab7b0794256f5b44c5f9769ea272e55cb6bcc1 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 31 Jan 2010 01:57:17 +0100 Subject: [PATCH 1/5] Framebuffer on PowerPC-based macs --- conf/powerpc-ieee1275.rmk | 5 + include/grub/ieee1275/ieee1275.h | 4 + kern/ieee1275/openfw.c | 23 ++- video/ieee1275.c | 298 +++++++++++++++++++++++++++++++ 4 files changed, 327 insertions(+), 3 deletions(-) create mode 100644 video/ieee1275.c diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index 23bd2d620..8622293ab 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -70,6 +70,11 @@ boot_mod_SOURCES = commands/boot.c lib/i386/pc/biosnum.c boot_mod_CFLAGS = $(COMMON_CFLAGS) boot_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += ieee1275_fb.mod +ieee1275_fb_mod_SOURCES = video/ieee1275.c +ieee1275_fb_mod_CFLAGS = $(COMMON_CFLAGS) +ieee1275_fb_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For linux.mod. linux_mod_SOURCES = loader/powerpc/ieee1275/linux.c linux_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h index 8b31e32e2..2aad199da 100644 --- a/include/grub/ieee1275/ieee1275.h +++ b/include/grub/ieee1275/ieee1275.h @@ -176,4 +176,8 @@ int EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t size); char *EXPORT_FUNC(grub_ieee1275_encode_devname) (const char *path); char *EXPORT_FUNC(grub_ieee1275_get_filename) (const char *path); +int EXPORT_FUNC(grub_ieee1275_devices_iterate) (int (*hook) + (struct grub_ieee1275_devalias * + alias)); + #endif /* ! GRUB_IEEE1275_HEADER */ diff --git a/kern/ieee1275/openfw.c b/kern/ieee1275/openfw.c index 5f0aad119..684680231 100644 --- a/kern/ieee1275/openfw.c +++ b/kern/ieee1275/openfw.c @@ -72,7 +72,7 @@ grub_children_iterate (char *devpath, if (grub_ieee1275_get_property (child, "device_type", childtype, IEEE1275_MAX_PROP_LEN, &actual)) - continue; + childtype[0] = 0; if (grub_ieee1275_package_to_path (child, childpath, IEEE1275_MAX_PATH_LEN, &actual)) @@ -82,7 +82,10 @@ grub_children_iterate (char *devpath, IEEE1275_MAX_PROP_LEN, &actual)) continue; - fullname = grub_xasprintf ("%s/%s", devpath, childname); + if (devpath[0] == '/' && devpath[1] == 0) + fullname = grub_xasprintf ("/%s", childname); + else + fullname = grub_xasprintf ("%s/%s", devpath, childname); if (!fullname) { grub_free (childname); @@ -99,7 +102,7 @@ grub_children_iterate (char *devpath, if (ret) break; } - while (grub_ieee1275_peer (child, &child)); + while (grub_ieee1275_peer (child, &child) != -1); grub_free (childname); grub_free (childpath); @@ -108,6 +111,20 @@ grub_children_iterate (char *devpath, return ret; } +int +grub_ieee1275_devices_iterate (int (*hook) (struct grub_ieee1275_devalias *alias)) +{ + auto int it_through (struct grub_ieee1275_devalias *alias); + int it_through (struct grub_ieee1275_devalias *alias) + { + if (hook (alias)) + return 1; + return grub_children_iterate (alias->name, it_through); + } + + return grub_children_iterate ("/", it_through); +} + /* Iterate through all device aliases. This function can be used to find a device of a specific type. */ int diff --git a/video/ieee1275.c b/video/ieee1275.c new file mode 100644 index 000000000..a9fc16a0f --- /dev/null +++ b/video/ieee1275.c @@ -0,0 +1,298 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#define grub_video_render_target grub_video_fbrender_target + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Only 8-bit indexed color is supported for now. */ + +static unsigned old_width, old_height; +static int restore_needed; +static char *display; + +static struct +{ + struct grub_video_mode_info mode_info; + struct grub_video_render_target *render_target; + grub_uint8_t *ptr; +} framebuffer; + +static grub_err_t +grub_video_ieee1275_set_palette (unsigned int start, unsigned int count, + struct grub_video_palette_data *palette_data); + +static void +set_video_mode (unsigned width __attribute__ ((unused)), + unsigned height __attribute__ ((unused))) +{ + /* TODO */ +} + +static void +find_display (void) +{ + auto int hook (struct grub_ieee1275_devalias *alias); + int hook (struct grub_ieee1275_devalias *alias) + { + if (grub_strcmp (alias->type, "display") == 0) + { + grub_dprintf ("video", "Found display %s\n", alias->name); + display = grub_strdup (alias->name); + return 1; + } + return 0; + } + + grub_ieee1275_devices_iterate (hook); +} + +static grub_err_t +grub_video_ieee1275_init (void) +{ + grub_memset (&framebuffer, 0, sizeof(framebuffer)); + return grub_video_fb_init (); +} + +static grub_err_t +grub_video_ieee1275_fini (void) +{ + if (restore_needed) + { + set_video_mode (old_width, old_height); + restore_needed = 0; + } + return grub_video_fb_fini (); +} + +static grub_err_t +grub_video_ieee1275_fill_mode_info (grub_ieee1275_phandle_t dev, + struct grub_video_mode_info *out) +{ + grub_uint32_t tmp; + + grub_memset (out, 0, sizeof (*out)); + + if (grub_ieee1275_get_integer_property (dev, "width", &tmp, + sizeof (tmp), 0)) + return grub_error (GRUB_ERR_IO, "Couldn't retrieve display width."); + out->width = tmp; + + if (grub_ieee1275_get_integer_property (dev, "height", &tmp, + sizeof (tmp), 0)) + return grub_error (GRUB_ERR_IO, "Couldn't retrieve display height."); + out->height = tmp; + + if (grub_ieee1275_get_integer_property (dev, "linebytes", &tmp, + sizeof (tmp), 0)) + return grub_error (GRUB_ERR_IO, "Couldn't retrieve display pitch."); + out->pitch = tmp; + + out->mode_type = GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + out->bpp = 8; + out->bytes_per_pixel = 1; + out->number_of_colors = 256; + + out->blit_format = grub_video_get_blit_format (out); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_ieee1275_setup (unsigned int width, unsigned int height, + unsigned int mode_type __attribute__ ((unused)), + unsigned int mode_mask __attribute__ ((unused))) +{ + grub_uint32_t current_width, current_height, address; + grub_err_t err; + grub_ieee1275_phandle_t dev; + + if (!display) + return grub_error (GRUB_ERR_IO, "Couldn't find display device."); + + if (grub_ieee1275_finddevice (display, &dev)) + return grub_error (GRUB_ERR_IO, "Couldn't open display device."); + + if (grub_ieee1275_get_integer_property (dev, "width", ¤t_width, + sizeof (current_width), 0)) + return grub_error (GRUB_ERR_IO, "Couldn't retrieve display width."); + + if (grub_ieee1275_get_integer_property (dev, "height", ¤t_height, + sizeof (current_width), 0)) + return grub_error (GRUB_ERR_IO, "Couldn't retrieve display height."); + + if ((width == current_width && height == current_height) + || (width == 0 && height == 0)) + { + grub_dprintf ("video", "IEEE1275: keeping current mode %dx%d\n", + current_width, current_height); + } + else + { + grub_dprintf ("video", "IEEE1275: Setting mode %dx%d\n", width, height); + /* TODO. */ + } + + err = grub_video_ieee1275_fill_mode_info (dev, &framebuffer.mode_info); + if (err) + { + grub_dprintf ("video", "IEEE1275: couldn't fill mode info\n"); + return err; + } + + if (grub_ieee1275_get_integer_property (dev, "address", &address, + sizeof (address), 0)) + return grub_error (GRUB_ERR_IO, "Couldn't retrieve display address."); + + framebuffer.ptr = (void *) address; + + grub_video_ieee1275_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, + grub_video_fbstd_colors); + + grub_dprintf ("video", "IEEE1275: initialising FB @ %p %dx%dx%d\n", + framebuffer.ptr, framebuffer.mode_info.width, + framebuffer.mode_info.height, framebuffer.mode_info.bpp); + + err = grub_video_fb_create_render_target_from_pointer + (&framebuffer.render_target, &framebuffer.mode_info, framebuffer.ptr); + + if (err) + { + grub_dprintf ("video", "IEEE1275: Couldn't create FB target\n"); + return err; + } + + err = grub_video_fb_set_active_render_target (framebuffer.render_target); + + if (err) + { + grub_dprintf ("video", "IEEE1275: Couldn't set FB target\n"); + return err; + } + + err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, + grub_video_fbstd_colors); + + if (err) + grub_dprintf ("video", "IEEE1275: Couldn't set palette\n"); + else + grub_dprintf ("video", "IEEE1275: Success\n"); + + return err; +} + +static grub_err_t +grub_video_ieee1275_swap_buffers (void) +{ + /* TODO: Implement buffer swapping. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_ieee1275_set_active_render_target (struct grub_video_render_target *target) +{ + if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY) + target = framebuffer.render_target; + + return grub_video_fb_set_active_render_target (target); +} + +static grub_err_t +grub_video_ieee1275_get_info_and_fini (struct grub_video_mode_info *mode_info, + void **framebuf) +{ + grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info)); + *framebuf = (char *) framebuffer.ptr; + + grub_video_fb_fini (); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_ieee1275_set_palette (unsigned int start, unsigned int count, + struct grub_video_palette_data *palette_data) +{ + grub_err_t err; + struct grub_video_palette_data fb_palette_data[256]; + + err = grub_video_fb_set_palette (start, count, palette_data); + if (err) + return err; + + grub_video_fb_get_palette (0, 256, fb_palette_data); + + /* TODO. */ + + return GRUB_ERR_NONE; +} + +static struct grub_video_adapter grub_video_ieee1275_adapter = + { + .name = "IEEE1275 video driver", + + .init = grub_video_ieee1275_init, + .fini = grub_video_ieee1275_fini, + .setup = grub_video_ieee1275_setup, + .get_info = grub_video_fb_get_info, + .get_info_and_fini = grub_video_ieee1275_get_info_and_fini, + .set_palette = grub_video_ieee1275_set_palette, + .get_palette = grub_video_fb_get_palette, + .set_viewport = grub_video_fb_set_viewport, + .get_viewport = grub_video_fb_get_viewport, + .map_color = grub_video_fb_map_color, + .map_rgb = grub_video_fb_map_rgb, + .map_rgba = grub_video_fb_map_rgba, + .unmap_color = grub_video_fb_unmap_color, + .fill_rect = grub_video_fb_fill_rect, + .blit_bitmap = grub_video_fb_blit_bitmap, + .blit_render_target = grub_video_fb_blit_render_target, + .scroll = grub_video_fb_scroll, + .swap_buffers = grub_video_ieee1275_swap_buffers, + .create_render_target = grub_video_fb_create_render_target, + .delete_render_target = grub_video_fb_delete_render_target, + .set_active_render_target = grub_video_ieee1275_set_active_render_target, + .get_active_render_target = grub_video_fb_get_active_render_target, + + .next = 0 + }; + +GRUB_MOD_INIT(ieee1275_fb) +{ + find_display (); + if (display) + grub_video_register (&grub_video_ieee1275_adapter); +} + +GRUB_MOD_FINI(ieee1275_fb) +{ + if (restore_needed) + { + set_video_mode (old_width, old_height); + restore_needed = 0; + } + if (display) + grub_video_unregister (&grub_video_ieee1275_adapter); + grub_free (display); +} From 58b78c121d96defe92ea8e60fe6b730cbd0f496d Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 5 Feb 2010 23:04:09 +0100 Subject: [PATCH 2/5] error on unsupported resolution --- video/ieee1275.c | 1 + 1 file changed, 1 insertion(+) diff --git a/video/ieee1275.c b/video/ieee1275.c index a9fc16a0f..21b65bd32 100644 --- a/video/ieee1275.c +++ b/video/ieee1275.c @@ -152,6 +152,7 @@ grub_video_ieee1275_setup (unsigned int width, unsigned int height, { grub_dprintf ("video", "IEEE1275: Setting mode %dx%d\n", width, height); /* TODO. */ + return grub_error (GRUB_ERR_IO, "can't set mode %dx%d", width, height); } err = grub_video_ieee1275_fill_mode_info (dev, &framebuffer.mode_info); From 7b5d0fe4440c8a061ab9a9cb3089b546cb9f88f6 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 6 Feb 2010 15:53:39 +0100 Subject: [PATCH 3/5] Increase heap limit --- kern/ieee1275/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kern/ieee1275/init.c b/kern/ieee1275/init.c index f3a4f4d81..75f261a71 100644 --- a/kern/ieee1275/init.c +++ b/kern/ieee1275/init.c @@ -38,11 +38,11 @@ #define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024) /* The maximum heap size we're going to claim */ -#define HEAP_MAX_SIZE (unsigned long) (4 * 1024 * 1024) +#define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) /* If possible, we will avoid claiming heap above this address, because it seems to cause relocation problems with OSes that link at 4 MiB */ -#define HEAP_MAX_ADDR (unsigned long) (4 * 1024 * 1024) +#define HEAP_MAX_ADDR (unsigned long) (32 * 1024 * 1024) extern char _start[]; extern char _end[]; From e0a3000a5cab9e6d306e8af82301f9b0f1087940 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 6 Feb 2010 16:00:56 +0100 Subject: [PATCH 4/5] ChangeLog --- ChangeLog.ofwfb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 ChangeLog.ofwfb diff --git a/ChangeLog.ofwfb b/ChangeLog.ofwfb new file mode 100644 index 000000000..49063b54d --- /dev/null +++ b/ChangeLog.ofwfb @@ -0,0 +1,16 @@ +2010-02-06 Vladimir Serbinenko + + * conf/powerpc-ieee1275.rmk (pkglib_MODULES): Add ieee1275_fb.mod. + (ieee1275_fb_mod_SOURCES): New variable. + (ieee1275_fb_mod_CFLAGS): Likewise. + (ieee1275_fb_mod_LDFLAGS): Likewise. + * include/grub/ieee1275/ieee1275.h (grub_ieee1275_devices_iterate): + New proto. + * kern/ieee1275/init.c (HEAP_MAX_SIZE): Increased. + (HEAP_MAX_ADDR): Likewise. + * kern/ieee1275/openfw.c (grub_children_iterate): Don't skip empty + type. + Correct stop condition. + (grub_ieee1275_devices_iterate): New function. + * video/ieee1275.c: New file. + From a3334e79e8dbba33491e6cdee540f20bc7eebd80 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 14 Feb 2010 20:03:19 +0100 Subject: [PATCH 5/5] Revert gratuituos change of alias.name --- kern/ieee1275/openfw.c | 18 ++---------------- video/ieee1275.c | 4 ++-- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/kern/ieee1275/openfw.c b/kern/ieee1275/openfw.c index 92ab2f683..ee8520359 100644 --- a/kern/ieee1275/openfw.c +++ b/kern/ieee1275/openfw.c @@ -68,7 +68,6 @@ grub_children_iterate (char *devpath, { struct grub_ieee1275_devalias alias; grub_ssize_t actual; - char *fullname; if (grub_ieee1275_get_property (child, "device_type", childtype, IEEE1275_MAX_PROP_LEN, &actual)) @@ -82,23 +81,10 @@ grub_children_iterate (char *devpath, IEEE1275_MAX_PROP_LEN, &actual)) continue; - if (devpath[0] == '/' && devpath[1] == 0) - fullname = grub_xasprintf ("/%s", childname); - else - fullname = grub_xasprintf ("%s/%s", devpath, childname); - if (!fullname) - { - grub_free (childname); - grub_free (childpath); - grub_free (childtype); - return 0; - } - alias.type = childtype; alias.path = childpath; - alias.name = fullname; + alias.name = childname; ret = hook (&alias); - grub_free (fullname); if (ret) break; } @@ -119,7 +105,7 @@ grub_ieee1275_devices_iterate (int (*hook) (struct grub_ieee1275_devalias *alias { if (hook (alias)) return 1; - return grub_children_iterate (alias->name, it_through); + return grub_children_iterate (alias->path, it_through); } return grub_children_iterate ("/", it_through); diff --git a/video/ieee1275.c b/video/ieee1275.c index 21b65bd32..3f0b93fb8 100644 --- a/video/ieee1275.c +++ b/video/ieee1275.c @@ -59,8 +59,8 @@ find_display (void) { if (grub_strcmp (alias->type, "display") == 0) { - grub_dprintf ("video", "Found display %s\n", alias->name); - display = grub_strdup (alias->name); + grub_dprintf ("video", "Found display %s\n", alias->path); + display = grub_strdup (alias->path); return 1; } return 0;