The initial problem

This weekend I’ve installed OpenBSD 6.3 on my old Macbook (Early 2008), and immediately I remember why I love this operating system. However, not everything is completely rosy.

After boot, the inteldrm driver appears to get confused and changes the console resolution to 848x480 (480i), but restricts this to the top left of the Macbook’s 1280x800 panel. Taking a look online, I found the following suggestion here: build a new kernel with DRMDEBUG enabled and consult the output.

Cheat sheet

# export KERNEL_CONFIGURATION_NAME=GENERIC_CUSTOM_NAME.MP
# cat << EOF > /sys/arch/$(machine)/conf/${KERNEL_CONFIGURATION_NAME}
> include "arch/i386/conf/GENERIC.MP"
>
> #option OPTION1
> #option OPTION2
>
> EOF
# mkdir /sys/arch/$(machine)/compile/${KERNEL_CONFIGURATION_NAME}
# cat << EOF > /sys/arch/$(machine)/compile/${KERNEL_CONFIGURATION_NAME}/Makefile
> .include "../Makefile.inc"
> EOF
# cd /sys/arch/$(machine)/compile/${KERNEL_CONFIGURATION_NAME}
# make obj
# make config
# make && make install
# reboot

The process

The first steps are as listed here:

$ cd /usr
$ cvs -qd anoncvs@anoncvs.ca.openbsd.org:/cvs checkout -rOPENBSD_6_3 -P src

This will take a while, and afterwards you’ll have all the source for the kernel and the core userland nicely in place.

Given that it’s been a long time since I’ve compiled an OpenBSD kernel, I thought I’d follow the instructions here pretty much verbatim to start with:

# cd /sys/arch/$(machine)/compile/GENERIC.MP
# make obj
# make config
# make && make install
# reboot

Fingers crossed, breath held and my Macbook comes back up. Success; I know I can build a kernel properly.

Configuration modification

Now, as I’d noted in the introduction, I needed to enable DRMDEBUG to enable the drm debug logging, and the way to do this is via options. Each of the option entries are provided as defines to the kernel build process, so in my case:

option DRMDEBUG

would result in:

-DDRMDEBUG

being added to the compiler flags.

Where to add this?

In the compilation steps, the only obviously variable item (besides the call to machine which will be the i386 for any invocations on this installation) is GENERIC.MP. If we take a look at this directory (ignoring source control files and the generated obj link) we find a single Makefile which is the tail end of the following include hierarchy:

  • /sys/arch/i386/compile/GENERIC.MP/Makefile
  • /sys/arch/i386/compile/Makefile.inc
  • /usr/src/share/mk/bsd.obj.mk
  • /usr/src/share/mk/bsd.own.mk
  • $MAKECONF or /etc/mk.conf if they exist

The target we are interested in, config, is defined in /sys/arch/i386/compile/Makefile.inc as:

config:
        config ${.CURDIR:M*.PROF:C/.*/-p/} -b ${.OBJDIR} \
                -s ${SYSDIR} ${CONFDIR}/${.CURDIR:T:S/.PROF$//}

This command makes use of config command to create a kernel build directory for a specified top-level source kernel source directory based on the configuration file. This configuration file (${CONFDIR}/${.CURDIR:T:S/.PROF$//}) is the next thing to look at.

Variable interpretation

To work out what this expands to, we need to know a few things from here, namely:

  • The built in .CURDIR variable, which is the path from which make is called
  • The :S modifier, which performs string replacement on a variable
  • The :T modifier, which replaces the variable with its last path component

Due to where we called make from, .CURDIR is now:

/sys/arch/i386/compile/GENERIC.MP

Based on this, CONFDIR (defined at the top of /sys/arch/i386/compile/Makefile.inc as the absolute path to ${.CURDIR}/../../conf), becomes:

/sys/arch/i386/conf

so we have:

/sys/arch/i386/conf/${.CURDIR:T:S/.PROF$//}

.CURDIR:T:S/.PROF$// is getting the last path component of /sys/arch/i386/compile/GENERIC.MP and removing the first (and only, based on the regex anchoring) occurence of .PROF.

NOTE: The removal of .PROF in this case isn’t relevant, but works in concert with ${.CURDIR:M*.PROF:C/.*/-p/} in the call to config to automatically include profiling code for appropriately named configurations.

Expanding this out, we now have:

/sys/arch/i386/conf/GENERIC.MP

Voila.

The contents of this configuration file (comments removed) are:

include "arch/i386/conf/GENERIC"

option          MULTIPROCESSOR

cpu*            at mainbus?

which is where we could set our options.

Custom configuration

I say could because it’s not a great idea to modify a configuration file that’s checked into source control, and from the use of include "arch/i386/conf/GENERIC" at the top of the file it’s clear that we can easily extend the configuration, creating our own custom configuration. All we need to do is:

  • create the configuration file
  • add a correspondingly named directory and Makefile under /sys/arch/$(machine)/compile

Given that I’m adding the DRMDEBUG flag, I’m going to name the configuration GENERIC_DRMDEBUG.MP, so the commands look like this:

# cat << EOF > /sys/arch/$(machine)/conf/GENERIC_DRMDEBUG.MP
> include "arch/i386/conf/GENERIC.MP"
>
> option  DRMDEBUG
> EOF
# mkdir /sys/arch/$(machine)/compile/GENERIC_DRMDEBUG.MP
# cat << EOF > /sys/arch/$(machine)/compile/GENERIC_DRMDEBUG.MP/Makefile
> .include "../Makefile.inc"
> EOF

Now, the compilation is almost exactly the same as the default:

# cd /sys/arch/$(machine)/compile/GENERIC_DRMDEBUG.MP
# make obj
# make config
# make && make install
# reboot

Once that’s done and the computer restarts, I can check the (voluminous) contents of /var/log/messages for the additional logging information, and hopefully this puts me on the path to working out my initial console resolution issue.