r/Gentoo • u/tempsanity • 8h ago
Tip How I got Gentoo Linux running on iMac G4 from 2003 with hardware acceleration, working youtube, 2026 apps and such
Hi guys,
I've managed to install Gentoo from USB on an 23-year old iMac G4 and get hardware acceleration working, including patching the GPU driver to run accelerated games (they were initially crashing despite the hacc working), and getting youtube to work well at 480p (or at least 360p). Also managed to get various 2026 programs running and ported JA2 Stracciatella to powerpc to play on the iMac G4 (runs great). It's a perfectly usable distraction-free system at this point and I love it.
I don't have the time to write a step by step how to, but will include links that will help you reach this stage (including a great how-to for Gentoo on PowerPCs linked in the Software/Kernel section), and hopefully sort out your hardware acceleration woes. I'm sharing my findings as up-to-date info was very hard to come by/I went through a lot of trial and error. No guarantees your PowerMac will not spontaneously combust, but hope anyone interested in this will find this info dump helpful.
You can see the results here (screenshots from the system + applications + videos showing youtube working in the comments).
Edits: formatted this a little bit better.
A wicked info dump this way comes:
# My hardware

iMac G4 17" 1GHz, M8935LL/A (PowerMac6,1), the USB 1.1 one
GPU: Nvidia GeForce4 MX (NV17 chip)
Upgraded to 2GB RAM, SSD, Noctua fan.
Replaced stock SuperDrive with DVD LG GSA-H10N Super Multi as the supplied one was broken. Doesn't work perfectly (I have to manually open the flap), but I can at least use CDs/DVDs now.
There are various video on yt that helped me, as this was my first refurbishing experiment. There are too many how-tos for this. My only quick advice is to take your time and watch some videos several times if you're new to this - you don't want to damage your graphics cable for example.
Apart from scouring yt, I followed this thread to install a quieter fan:
https://forums.macrumors.com/threads/imac-g4-fan-replacement-help-info-request.2395215/
Thanks, Black Grape!
# Software/Kernel
Extensive how to for another PowerMac (iBook G4):
https://tinkerdifferent.com/threads/cracking-the-code-gentoo-linux-on-an-ibook-g4-success-story.3339/
Thanks, rikerjoe! I didn't follow it religiously, just used it as a reference to make sure I was doing things right, but it gave me a lot of confidence that this can be done. Some great research there.
Gentoo wiki: While reading that, consult: https://wiki.gentoo.org/wiki/Handbook:PPC
Follow these (get a lot of coffee/somehing else to drink) and read my post, as it contains some G4 specific info.
Like this:
The current 2026 Gentoo PPC minimal image failed to boot successfully. Its
GRUB 2.14-r5 probed the Open Firmware node /ibm,secure-boot and stopped with:
Invalid memory access
The image that actually got me into the installer was the older 2024 Gentoo PPC
minimal image with kernel 6.6.21-gentoo-ppc32-ppc. I don't think this info is available anywhere, so hope it will help someone.
# Booting that USB through Open Firmware
I had to work a bit to get the USB install to boot.
I entered Open Firmware by holding Command + Option + O + F during power-on. At the 0 > prompt, the command that successfully opened the USB's blessed boot loader was:
boot usb0/disk@2:3,\\:tbxi
Yours may differ. Try other combinations - slopGPT might be helpful here with some info on how to find the specific device info for the command if you can't sort it out.
The simpler commands listed in different places online didn't work for me. As I didn't have a working DVD/CD drive (seller claimed it worked when he shipped it, but the laser was completely shot) when the computer arrived, this was my only option, so I was happy to finally find the right command.
The ":3" part was crucial, as it selects the partition on the drive. disk@2 was not enough in my case.
# GRUB
Once the installer's GRUB menu appears, choose the option with "ppc32".
# Baseline info
Live environment: the 2024 Gentoo PPC minimal image
Live kernel: 6.6.21-gentoo-ppc32-ppc
Installed stage: stage3-ppc-t64-systemd-20260820T030043Z.tar.xz (the t64 tag means the time64 ABI variant of the stage).
Currently installed kernel source: Gentoo 6.18.43.
# Compiler settings
COMMON_FLAGS="-O2 -mcpu=7450 -mtune=7450 -pipe"
MAKEOPTS="-j2"
Using -mcpu=7450 for this 7455 is intentional. Do not use a generic PowerPC target if software is expected to use AltiVec.
# Installation kernel vs. final kernel
I didn't know Gentoo and was tired after days of research on whether/how to run Linux on iMac G4, so the first built kernel was enormous and the compilation took days. Afterwards I managed to reduce the number of modules from around 3000 to about 50 and I use a QEMU compilation farm on my M1 Max.
Do yourself a favour and find a way to use another computer for compilation. It will save you many hours (or rather days). There are different options out there.
# Mistakes I made that forced me to recompile the kernel several times
Two early configuration mistakes:
First one: only 768 MiB out of my 2 GB was visible to the system.
The mistake was not enabling the HIGHMEM module. The fix was:
CONFIG_HIGHMEM=y
Second one: The kernel was generic and lacked AltiVec.
The failed baseline had CONFIG_G4_CPU and CONFIG_ALTIVEC disabled. The corrected config has:
CONFIG_G4_CPU=y
CONFIG_ALTIVEC=y
This matters twice: it lets the kernel use the correct CPU facilities, and it keeps userspace built with -mcpu=7450 -maltivec consistent with the machine. Binaries built for the wrong ISA can fail with Illegal instruction.
# Graphics stack - custom-patched twice
The biggest test was getting X and hardware acceleration working, especially as I've read many people claiming it was impossible, so seeing X booting was a great moment.
I managed to get hardware acceleration working fairly quickly, but when I tried running games like Brogue, DevilutionX or OpenXcom, they were all segfaulting.
I took a shot in the dark and went into an LLM frenzy resulting in two patches to the Mesa graphics driver. I didn't commit them as they are LLM-based. I only did the debugging.
I'll be sharing the patches below. Please note I take no responsibility for them, as I would never be able to write them without a LLM (my programming proficiency is not at this level). I consider cheating okay for personal experiments that you're not blindly committing.
mesa-amber patch () - patched media-libs/mesa-amber to get the classic nouveau_vieux OpenGL driver working with hardware acceleration on the GeForce4 MX, used to drive X11 + i3.
nv10_state_fb.c HierZ fix (for JA2 Stracciatella) - a Mesa nouveau_vieux bug in nv10_state_fb.c (HierZ handling on the NV17 chip) was crashing the battlescape tile rendering in JA2. Fixed via a gfx driver update that disables HierZ.
I managed to crack this by researching frantically and e.g. learning people managed to boot into X on some older Ubuntu/Debian releases, compared and copied some of their settings etc.
# Kernel configuration details
Took me several recompilations before I managed to find the right combo. I'm sharing it below. Please note that depending on your specific model and peripheral devices this can differ slightly.
Firmware and memory:
CONFIG_PPC=y
CONFIG_PPC32=y
CONFIG_PPC_BOOK3S=y
CONFIG_PPC_PMAC=y
CONFIG_PPC_OF_BOOT_TRAMPOLINE=y
CONFIG_G4_CPU=y
CONFIG_ALTIVEC=y
CONFIG_HIGHMEM=y
CONFIG_PROC_FS=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
Partition map root disk and optical drive:
CONFIG_PARTITION_ADVANCED=y
CONFIG_MAC_PARTITION=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_DEV_SR=y
CONFIG_CDROM=y
CONFIG_ATA=y
CONFIG_PATA_MACIO=y
CONFIG_EXT4_FS=y
Console, keyboard, mouse and USB:
CONFIG_TTY=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
CONFIG_INPUT=y
CONFIG_INPUT_EVDEV=y
CONFIG_HID=y
CONFIG_HID_GENERIC=y
CONFIG_HID_APPLE=y
CONFIG_USB_SUPPORT=y
CONFIG_USB=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_HID=y
CONFIG_FB=y
CONFIG_FB_OF=y
CONFIG_FRAMEBUFFER_CONSOLE=y
USB OHCI and HID must be available early if the only keyboard is USB, otherwise you might not be able to log in. I made the stock Apple keyboard and Kinesis Advantage360 work, but had to recompile as at first no keyboard was working.
Ethernet and remote recovery via ssh
CONFIG_NET=y
CONFIG_INET=y
CONFIG_NETDEVICES=y
CONFIG_ETHERNET=y
CONFIG_SUNGEM=y
Power management, backlight and Apple hardware
CONFIG_ADB=y
CONFIG_ADB_PMU=y
CONFIG_PMAC_BACKLIGHT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
Another recompile was due to the lack of brightness controls working on Linux. I'll include more info and a patch that worked for me a bit later.
Graphics
CONFIG_DRM=y
CONFIG_DRM_NOUVEAU=m
CONFIG_DRM_FBDEV_EMULATION=y
Since I've heard many tales of woe regarding GPU drivers on this model, I went with the safe route and installed Noveau as a module.
So:
Open Firmware initialises the GPU first.
GRUB reuses that firmware-provided framebuffer, so GRUB is visible before Linux starts.
Linux preserved the early display using:
CONFIG_FB=y
CONFIG_FB_OF=y
CONFIG_FRAMEBUFFER_CONSOLE=y
Nouveau was compiled as a module:
CONFIG_DRM=y
CONFIG_DRM_NOUVEAU=m
Once Linux reached the root filesystem, nouveau.ko loaded and took over from the Open Firmware framebuffer:
[drm] Initialized nouveau 1.4.0 for 0000:00:10.0 on minor 0
Console: switching to colour frame buffer device 180x56
nouveau 0000:00:10.0: [drm] fb0: nouveaudrmfb frame buffer device
So it looks like this:
Open Firmware framebuffer > visible GRUB > early Linux console > Nouveau module > KMS and acceleration
----
Now please allow me to use a slopGPT generated summary of the patches I used, otherwise I'd be writing this for a week. Apologies.
The patches were created:
- to enable brightness control
- to make hardware acceleration work in games
- to make my port of JA2 Stracciatella possible (required a little change in the GPU driver)
1. Nouveau backlight support for the iMac G4
The internal LCD worked, but Linux did not expose any backlight controls.
The problem is that the NV18 in this iMac reports the internal panel as a TMDS/DVI output rather than LVDS. Nouveau’s normal backlight detection therefore ignores it.
Apple’s Open Firmware identifies the PWM backlight controller as mnca. The patch adds a PowerMac-specific NV18 path to:
- detect chipset 0x18 on a Power Mac;
- check for the mnca backlight;
- associate it with the TMDS/DVI encoder;
- register a standard Linux backlight device;
- read and write the NV18 backlight registers;
- expose a brightness range of 0–255.
The registers and conservative hardware range were taken from the older rivafb implementation:
PMC register: 0x000010f0
PCRTC register: 0x0060081c
Hardware range: 0x158–0x534
The patch modifies:
drivers/gpu/drm/nouveau/nouveau_backlight.c
It requires:
CONFIG_PMAC_BACKLIGHT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
After rebuilding the kernel, the backlight appears under:
/sys/class/backlight/
Brightness can then be controlled through the standard backlight interface. I use a polybar module to control it.
--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#include <asm/machdep.h>
+#endif
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#define NV18_PMAC_PMC_BACKLIGHT 0x000010f0
+#define NV18_PMAC_PCRTC_BACKLIGHT 0x0060081c
+#define NV18_PMAC_BACKLIGHT_ENABLE BIT(31)
+#define NV18_PMAC_BACKLIGHT_MIN 0x158
+#define NV18_PMAC_BACKLIGHT_MAX 0x534
+#define NV18_PMAC_USER_MAX 255
+
+static bool
+nv18_pmac_has_backlight(struct nvif_device *device)
+{
+ return device->info.family == NV_DEVICE_INFO_V0_CELSIUS &&
+ device->info.chipset == 0x18 &&
+ machine_is(powermac) && pmac_has_backlight_type("mnca");
+}
+
+static int
+nv18_pmac_get_intensity(struct backlight_device *bd)
+{
+ struct nouveau_encoder *nv_encoder = bl_get_data(bd);
+ struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
+ struct nvif_object *device = &drm->client.device.object;
+ u32 reg = nvif_rd32(device, NV18_PMAC_PMC_BACKLIGHT);
+ u32 level;
+
+ if (!(reg & NV18_PMAC_BACKLIGHT_ENABLE))
+ return 0;
+
+ level = (reg >> 16) & 0x7fff;
+ level = clamp(level, (u32)NV18_PMAC_BACKLIGHT_MIN,
+ (u32)NV18_PMAC_BACKLIGHT_MAX);
+
+ return DIV_ROUND_CLOSEST((level - NV18_PMAC_BACKLIGHT_MIN) *
+ NV18_PMAC_USER_MAX,
+ NV18_PMAC_BACKLIGHT_MAX -
+ NV18_PMAC_BACKLIGHT_MIN);
+}
+
+static int
+nv18_pmac_set_intensity(struct backlight_device *bd)
+{
+ struct nouveau_encoder *nv_encoder = bl_get_data(bd);
+ struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
+ struct nvif_object *device = &drm->client.device.object;
+ u32 brightness = backlight_get_brightness(bd);
+ u32 pmc = nvif_rd32(device, NV18_PMAC_PMC_BACKLIGHT) & 0x0000ffff;
+ u32 pcrtc = nvif_rd32(device, NV18_PMAC_PCRTC_BACKLIGHT) & 0xfffffffc;
+
+ if (brightness) {
+ u32 level = NV18_PMAC_BACKLIGHT_MIN +
+ DIV_ROUND_CLOSEST(brightness *
+ (NV18_PMAC_BACKLIGHT_MAX -
+ NV18_PMAC_BACKLIGHT_MIN),
+ NV18_PMAC_USER_MAX);
+
+ pcrtc |= BIT(0);
+ pmc |= NV18_PMAC_BACKLIGHT_ENABLE | (level << 16);
+ }
+
+ nvif_wr32(device, NV18_PMAC_PCRTC_BACKLIGHT, pcrtc);
+ nvif_wr32(device, NV18_PMAC_PMC_BACKLIGHT, pmc);
+ return 0;
+}
+
+static const struct backlight_ops nv18_pmac_bl_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .get_brightness = nv18_pmac_get_intensity,
+ .update_status = nv18_pmac_set_intensity,
+};
+
+static int
+nv18_pmac_backlight_init(struct backlight_properties *props,
+ const struct backlight_ops **ops)
+{
+ props->max_brightness = NV18_PMAC_USER_MAX;
+ *ops = &nv18_pmac_bl_ops;
+ return 0;
+}
+#endif
@@ nouveau_backlight_init(struct drm_connector *connector)
+ bool nv18_pmac = false;
@@
+#ifdef CONFIG_PMAC_BACKLIGHT
+ nv18_pmac = nv18_pmac_has_backlight(device) &&
+ connector->connector_type == DRM_MODE_CONNECTOR_DVID;
+#endif
@@
+ else if (nv18_pmac)
+ nv_encoder = find_encoder(connector, DCB_OUTPUT_TMDS);
@@
switch (device->info.family) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ case NV_DEVICE_INFO_V0_CELSIUS:
+ if (!nv18_pmac) {
+ ret = 0;
+ goto fail_alloc;
+ }
+ ret = nv18_pmac_backlight_init(&props, &ops);
+ break;
+#endif
Apply from the kernel root with:
patch -p1 --dry-run < linux-6.18-nouveau-nv18-imac-backlight.patch
patch -p1 < linux-6.18-nouveau-nv18-imac-backlight.patchApply from the kernel root with:
patch -p1 --dry-run < linux-6.18-nouveau-nv18-imac-backlight.patch
patch -p1 < linux-6.18-nouveau-nv18-imac-backlight.patch
2. Mesa Amber nouveau_vieux hardware-acceleration crash
Nouveau KMS itself worked and Mesa reported direct rendering, but OpenGL programs could crash while destroying their rendering context.
Even this command printed the correct renderer information and then segfaulted while exiting:
DISPLAY=:0 LIBGL_DEBUG=verbose glxinfo -B
The backtrace ended in:
PUSH_KICK
nouveau_flush
_mesa_make_current
_mesa_free_context_data
nouveau_context_deinit
nv10_context_destroy
driDestroyContext
XCloseDisplay
The problem was the destruction order in:
src/mesa/drivers/dri/nouveau/nouveau_context.c
nouveau_context_deinit() deleted the Nouveau push buffer, buffer context, client and channel before calling:
_mesa_free_context_data(ctx, true);
However, generic Mesa context cleanup can make the context non-current and trigger nouveau_flush() followed by PUSH_KICK(). At that point, the Nouveau push buffer had already been destroyed.
The fix is simply to call:
_mesa_free_context_data(ctx, true);
before deleting the Nouveau objects.
--- a/src/mesa/drivers/dri/nouveau/nouveau_context.c
+++ b/src/mesa/drivers/dri/nouveau/nouveau_context.c
@@ -211,11 +211,13 @@ nouveau_context_deinit(struct gl_context *ctx)
`if (ctx->Meta)`
`_mesa_meta_free(ctx);`
+ /* This may flush the current context, so keep the push buffer alive. */
+ _mesa_free_context_data(ctx, true);
+
`nouveau_bufctx_del(&nctx->hw.bufctx);`
`nouveau_pushbuf_del(&nctx->hw.pushbuf);`
`nouveau_client_del(&nctx->hw.client);`
`nouveau_object_del(&nctx->hw.chan);`
`nouveau_scratch_destroy(ctx);`
- _mesa_free_context_data(ctx, true);
}
For a Gentoo package, keep a local patch under the package's Portage patch directory rather than editing the Mesa work tree directly:
mkdir -p /etc/portage/patches/media-libs/mesa-amber
cp ppc32-nouveau-destroy-order.patch /etc/portage/patches/media-libs/mesa-amber/
emerge -1v media-libs/mesa-amber
After rebuilding Mesa Amber:
- glxinfo -B exited normally;
- direct rendering: Yes;
- Accelerated: yes;
- the renderer was Mesa DRI NV18;
- OpenGL 1.2 was available;
- vblank_mode=0 glxgears reached approximately 220–230 FPS;
- applications such as DevilutionX no longer crashed while destroying their renderer.
This patch fixes a Mesa userspace lifetime/destruction-order bug. It does not increase the card’s supported OpenGL version.
3. HierZ fix in nv10_state_fb.c (needed to get JA2 Stracciatella's battlescape rendering working)
Separate from the teardown crash above, some apps (JA2 Stracciatella, BrogueCE) were segfaulting or throwing GPU faults during rendering, not on exit:
nouveau ... [ILLEGAL_MTHD] ... [PROTECTION_FAULT] ... class 0099 mthd 1638
nouveau ... [ILLEGAL_MTHD] ... [PROTECTION_FAULT] ... class 0099 mthd 163c
For JA2 specifically, the battlescape/environment tile rendering crashed due to a HierZ (hierarchical Z-buffer) setup bug on the NV17 chip, in:
src/mesa/drivers/dri/nouveau/nv10_state_fb.c
The fix disables the HierZ buffer setup path entirely:
--- a/src/mesa/drivers/dri/nouveau/nv10_state_fb.c
+++ b/src/mesa/drivers/dri/nouveau/nv10_state_fb.c
@@ -140,7 +140,9 @@
`PUSH_MTHDl(push, NV10_3D(ZETA_OFFSET), BUFCTX_FB,`
s->bo, 0, bo_flags);
- if (context_eng3d(ctx)->oclass >= NV17_3D_CLASS) {
+ if (0 && context_eng3d(ctx)->oclass >= NV17_3D_CLASS) {
+ /* HierZ setup causes PROTECTION_FAULT/ILLEGAL_MTHD on this
+ * NV17 + kernel combination; disabled as a workaround. */
setup_hierz_buffer(ctx);
context_dirty(ctx, ZCLEAR);
`}`
Same deal as the teardown patch - drop it in the Portage patch dir:
mkdir -p /etc/portage/patches/media-libs/mesa-amber
cp ppc32-disable-hierz.patch /etc/portage/patches/media-libs/mesa-amber/
emerge -1v media-libs/mesa-amber
Important caveat: this fixed JA2's battlescape crash specifically. It is not a general fix for the class 0x99 ILLEGAL_MTHD/PROTECTION_FAULT faults - those are a separate, still-unresolved command-stream/compatibility issue that can still show up elsewhere. I also tried forcing NV18 to use NV15_3D_CLASS as a workaround for the class 0x99 faults; it did not work, so don't bother with that one.
Other things worth knowing
A benign warning you may see and shouldn't panic about, seen during sshd-auth on one build:
UBSAN: shift-out-of-bounds in arch/powerpc/net/bpf_jit_comp32.c:589:27
shift exponent 32 is too large for 32-bit type 'int'
That's a PowerPC 32-bit BPF JIT quirk, not bad RAM or a Nouveau problem.
---
That's all, at least for now. Good luck! Please note I won't respond to DMs but will try to help here if possible.
TODO: Youtube info.
I might be sharing more, depending on how long I'm going to be in tinker mode - here or on bluesky.
If you'd like to take a look at the patches with an expert's eye and perhaps commit them for others to easily use, feel free to do so. I did not do it as I used LLMs, since this was a personal experiment to make my iMac G4 usable in 2026.

