#include <grub/command.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
- #include <grub/i386/pc/serial.h>
++#include <grub/serial.h>
+
#include <grub/video.h>
#ifdef GRUB_MACHINE_PCBIOS
#include <grub/machine/biosnum.h>
}
static grub_err_t
-grub_netbsd_boot (void)
+grub_netbsd_setup_video (void)
{
- struct grub_netbsd_bootinfo *bootinfo;
- int count = 0;
- struct grub_netbsd_btinfo_mmap_header *mmap;
- struct grub_netbsd_btinfo_mmap_entry *pm;
- void *curarg;
-
- auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
- int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)),
- grub_uint64_t size __attribute__ ((unused)),
- grub_uint32_t type __attribute__ ((unused)))
- {
- count++;
- return 0;
- }
-
- auto int NESTED_FUNC_ATTR fill_hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
- int NESTED_FUNC_ATTR fill_hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
- {
- pm->addr = addr;
- pm->len = size;
+ struct grub_video_mode_info mode_info;
+ void *framebuffer;
+ const char *modevar;
+ struct grub_netbsd_btinfo_framebuf params;
+ grub_err_t err;
+ grub_video_driver_id_t driv_id;
- switch (type)
- {
- case GRUB_MACHINE_MEMORY_AVAILABLE:
- pm->type = NETBSD_MMAP_AVAILABLE;
- break;
+ modevar = grub_env_get ("gfxpayload");
- case GRUB_MACHINE_MEMORY_ACPI:
- pm->type = NETBSD_MMAP_ACPI;
- break;
+ /* Now all graphical modes are acceptable.
+ May change in future if we have modes without framebuffer. */
+ if (modevar && *modevar != 0)
+ {
+ char *tmp;
- tmp = grub_malloc (grub_strlen (modevar)
- + sizeof (";" NETBSD_DEFAULT_VIDEO_MODE));
++ tmp = grub_xasprintf ("%s;" NETBSD_DEFAULT_VIDEO_MODE, modevar);
+ if (! tmp)
+ return grub_errno;
- grub_sprintf (tmp, "%s;" NETBSD_DEFAULT_VIDEO_MODE, modevar);
+ err = grub_video_set_mode (tmp, 0, 0);
+ grub_free (tmp);
+ }
+ else
+ err = grub_video_set_mode (NETBSD_DEFAULT_VIDEO_MODE, 0, 0);
- case GRUB_MACHINE_MEMORY_NVS:
- pm->type = NETBSD_MMAP_NVS;
- break;
+ if (err)
+ return err;
- default:
- pm->type = NETBSD_MMAP_RESERVED;
- break;
- }
- pm++;
+ driv_id = grub_video_get_driver_id ();
+ if (driv_id == GRUB_VIDEO_DRIVER_NONE)
+ return GRUB_ERR_NONE;
- return 0;
- }
+ err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
- grub_mmap_iterate (count_hook);
+ if (err)
+ return err;
- if (kern_end + sizeof (struct grub_netbsd_btinfo_rootdevice)
- + sizeof (struct grub_netbsd_bootinfo)
- + sizeof (struct grub_netbsd_btinfo_mmap_header)
- + count * sizeof (struct grub_netbsd_btinfo_mmap_entry)
- > grub_os_area_addr + grub_os_area_size)
- return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+ params.width = mode_info.width;
+ params.height = mode_info.height;
+ params.bpp = mode_info.bpp;
+ params.pitch = mode_info.pitch;
+ params.flags = 0;
- curarg = mmap = (struct grub_netbsd_btinfo_mmap_header *) kern_end;
- pm = (struct grub_netbsd_btinfo_mmap_entry *) (mmap + 1);
+ params.fbaddr = (grub_addr_t) framebuffer;
- grub_mmap_iterate (fill_hook);
- mmap->common.type = NETBSD_BTINFO_MEMMAP;
- mmap->common.len = (char *) pm - (char *) mmap;
- mmap->count = count;
- curarg = pm;
+ params.red_mask_size = mode_info.red_mask_size;
+ params.red_field_pos = mode_info.red_field_pos;
+ params.green_mask_size = mode_info.green_mask_size;
+ params.green_field_pos = mode_info.green_field_pos;
+ params.blue_mask_size = mode_info.blue_mask_size;
+ params.blue_field_pos = mode_info.blue_field_pos;
- if (netbsd_root)
+#ifdef GRUB_MACHINE_PCBIOS
+ /* VESA packed modes may come with zeroed mask sizes, which need
+ to be set here according to DAC Palette width. If we don't,
+ this results in Linux displaying a black screen. */
+ if (mode_info.bpp <= 8 && driv_id == GRUB_VIDEO_DRIVER_VBE)
{
- struct grub_netbsd_btinfo_rootdevice *rootdev;
+ struct grub_vbe_info_block controller_info;
+ int status;
+ int width = 8;
+
+ status = grub_vbe_bios_get_controller_info (&controller_info);
- rootdev = (struct grub_netbsd_btinfo_rootdevice *) curarg;
+ if (status == GRUB_VBE_STATUS_OK &&
+ (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH))
+ status = grub_vbe_bios_set_dac_palette_width (&width);
- rootdev->common.len = sizeof (struct grub_netbsd_btinfo_rootdevice);
- rootdev->common.type = NETBSD_BTINFO_ROOTDEVICE;
- grub_strncpy (rootdev->devname, netbsd_root, sizeof (rootdev->devname));
+ if (status != GRUB_VBE_STATUS_OK)
+ /* 6 is default after mode reset. */
+ width = 6;
- bootinfo = (struct grub_netbsd_bootinfo *) (rootdev + 1);
- bootinfo->bi_count = 2;
- bootinfo->bi_data[0] = mmap;
- bootinfo->bi_data[1] = rootdev;
+ params.red_mask_size = params.green_mask_size
+ = params.blue_mask_size = width;
}
- else
+#endif
+
+ err = grub_bsd_add_meta (NETBSD_BTINFO_FRAMEBUF, ¶ms, sizeof (params));
+ return err;
+}
+
+static grub_err_t
+grub_netbsd_add_modules (void)
+{
+ struct netbsd_module *mod;
+ unsigned modcnt = 0;
+ struct grub_netbsd_btinfo_modules *mods;
+ unsigned i;
+ grub_err_t err;
+
+ for (mod = netbsd_mods; mod; mod = mod->next)
+ modcnt++;
+
+ mods = grub_malloc (sizeof (*mods) + sizeof (mods->mods[0]) * modcnt);
+ if (!mods)
+ return grub_errno;
+
+ mods->num = modcnt;
+ mods->last_addr = kern_end;
+ for (mod = netbsd_mods, i = 0; mod; i++, mod = mod->next)
+ mods->mods[i] = mod->mod;
+
+ err = grub_bsd_add_meta (NETBSD_BTINFO_MODULES, mods,
+ sizeof (*mods) + sizeof (mods->mods[0]) * modcnt);
+ grub_free (mods);
+ return err;
+}
+
+static grub_err_t
+grub_netbsd_boot (void)
+{
+ struct grub_netbsd_bootinfo *bootinfo;
+ void *curarg, *arg0;
+ grub_addr_t arg_target, stack_target;
+ grub_uint32_t *stack;
+ grub_err_t err;
+ struct grub_relocator32_state state;
+ grub_size_t tag_buf_len = 0;
+ int tag_count = 0;
+
+ err = grub_bsd_add_mmap ();
+ if (err)
+ return err;
+
+ err = grub_netbsd_setup_video ();
+ if (err)
{
- bootinfo = (struct grub_netbsd_bootinfo *) curarg;
- bootinfo->bi_count = 1;
- bootinfo->bi_data[0] = mmap;
+ grub_print_error ();
+ grub_printf ("Booting however\n");
+ grub_errno = GRUB_ERR_NONE;
}
- grub_video_set_mode ("text", 0, 0);
+ err = grub_netbsd_add_modules ();
+ if (err)
+ return err;
- grub_unix_real_boot (entry, bootflags, 0, bootinfo,
- 0, (grub_uint32_t) (grub_mmap_get_upper () >> 10),
- (grub_uint32_t) (grub_mmap_get_lower () >> 10));
+ {
+ struct bsd_tag *tag;
+ tag_buf_len = 0;
+ for (tag = tags; tag; tag = tag->next)
+ {
+ tag_buf_len = ALIGN_VAR (tag_buf_len
+ + sizeof (struct grub_netbsd_btinfo_common)
+ + tag->len);
+ tag_count++;
+ }
+ }
- /* Not reached. */
- return GRUB_ERR_NONE;
+ arg_target = kern_end;
+ err = grub_relocator_alloc_chunk_addr (relocator, &curarg,
+ arg_target, tag_buf_len
+ + sizeof (struct grub_netbsd_bootinfo)
+ + tag_count * sizeof (grub_uint32_t));
+ if (err)
+ return err;
+
+ arg0 = curarg;
+ bootinfo = (void *) ((grub_uint8_t *) arg0 + tag_buf_len);
+
+ {
+ struct bsd_tag *tag;
+ unsigned i;
+
+ bootinfo->bi_count = tag_count;
+ for (tag = tags, i = 0; tag; i++, tag = tag->next)
+ {
+ struct grub_netbsd_btinfo_common *head = curarg;
+ bootinfo->bi_data[i] = ((grub_uint8_t *) curarg - (grub_uint8_t *) arg0)
+ + arg_target;
+ head->type = tag->type;
+ head->len = tag->len + sizeof (*head);
+ curarg = head + 1;
+ grub_memcpy (curarg, tag->data, tag->len);
+ curarg = (grub_uint8_t *) curarg + tag->len;
+ }
+ }
+
+ err = grub_relocator_alloc_chunk_align (relocator, (void **) &stack,
+ &stack_target, 0x10000, 0x90000,
+ 7 * sizeof (grub_uint32_t), 4,
+ GRUB_RELOCATOR_PREFERENCE_NONE);
+ if (err)
+ return err;
+
+#ifdef GRUB_MACHINE_EFI
+ if (! grub_efi_finish_boot_services ())
+ grub_fatal ("cannot exit boot services");
+#endif
+
+ state.eip = entry;
+ state.esp = stack_target;
+ stack[0] = entry;
+ stack[1] = bootflags;
+ stack[2] = 0;
+ stack[3] = ((grub_uint8_t *) bootinfo - (grub_uint8_t *) arg0) + arg_target;
+ stack[4] = 0;
+ stack[5] = grub_mmap_get_upper () >> 10;
+ stack[6] = grub_mmap_get_lower () >> 10;
+
+ return grub_relocator32_boot (relocator, state);
}
static grub_err_t
state.eip = grub_xnu_entry_point;
state.eax = grub_xnu_arg1;
- return grub_relocator32_boot (grub_xnu_heap_start, grub_xnu_heap_will_be_at,
- state);
+ return grub_relocator32_boot (grub_xnu_relocator, state);
+}
+
+/* Setup video for xnu. */
+static grub_err_t
+grub_xnu_set_video (struct grub_xnu_boot_params *params)
+{
+ struct grub_video_mode_info mode_info;
+ int ret;
+ char *tmp, *modevar;
+ void *framebuffer;
+ grub_err_t err;
+
+ modevar = grub_env_get ("gfxpayload");
+ /* Consider only graphical 32-bit deep modes. */
+ if (! modevar || *modevar == 0)
+ err = grub_video_set_mode (DEFAULT_VIDEO_MODE,
+ GRUB_VIDEO_MODE_TYPE_PURE_TEXT
+ | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK,
+ 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS);
+ else
+ {
- tmp = grub_malloc (grub_strlen (modevar)
- + sizeof (DEFAULT_VIDEO_MODE) + 1);
++ tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
+ if (! tmp)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't allocate temporary storag");
- grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
+ err = grub_video_set_mode (tmp,
+ GRUB_VIDEO_MODE_TYPE_PURE_TEXT
+ | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK,
+ 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS);
+ grub_free (tmp);
+ }
+
+ if (err)
+ return err;
+
+ if (grub_xnu_bitmap)
+ {
+ int x, y;
+
+ x = mode_info.width - grub_xnu_bitmap->mode_info.width;
+ x /= 2;
+ y = mode_info.height - grub_xnu_bitmap->mode_info.height;
+ y /= 2;
+ err = grub_video_blit_bitmap (grub_xnu_bitmap,
+ GRUB_VIDEO_BLIT_REPLACE,
+ x > 0 ? x : 0,
+ y > 0 ? y : 0,
+ x < 0 ? -x : 0,
+ y < 0 ? -y : 0,
+ min (grub_xnu_bitmap->mode_info.width,
+ mode_info.width),
+ min (grub_xnu_bitmap->mode_info.height,
+ mode_info.height));
+ if (err)
+ {
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ grub_xnu_bitmap = 0;
+ }
+ err = GRUB_ERR_NONE;
+ }
+
+ ret = grub_video_get_info_and_fini (&mode_info, &framebuffer);
+ if (ret)
+ return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters");
+
+ params->lfb_width = mode_info.width;
+ params->lfb_height = mode_info.height;
+ params->lfb_depth = mode_info.bpp;
+ params->lfb_line_len = mode_info.pitch;
+
+ params->lfb_base = PTR_TO_UINT32 (framebuffer);
+ params->lfb_mode = grub_xnu_bitmap
+ ? GRUB_XNU_VIDEO_SPLASH : GRUB_XNU_VIDEO_TEXT_IN_VIDEO;
+
+ return GRUB_ERR_NONE;
}
/* Boot xnu. */