The Uncoöperative Organization

Programming and other human stuff.

UEFI Debugging Tools

| Comments

One of the many things I work on is UEFI support. It’s an interesting thing to work on, in part because there’s a lot of new development and it’s at a fairly low level, which is just the sort of thing I like.

Often during UEFI development, we’ll see a bug and need to diagnose whether it’s a problem with the hardware, the firmware, the bootloader, the OS kernel, or even a userland program. One case of this is when console graphics don’t work right.

A recent bug reported that console graphics weren’t working due to an invalid pixel format being chosen. While diagnosing this problem, there are a couple of things that could go wrong. The firmware driver could be reporting the wrong modes, the bootloader could have a bug where it’s querying the modes incorrectly or misinforming the kernel as to the mode chosen, or the kernel could have a bug where it uses the mode incorrectly. It’s also possible that the console works until a KMS driver - that is, a native driver for the card - is loaded.

In UEFI, console graphics involves every part of the stack. The system firmware provides an API known as Graphics Output Protocol, or GOP. The algorithm used by the bootloader basically looks like this somewhat simplified function:

set_mode.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
int gop_enable(struct graphics *graphics, struct kernel_params *kernel_params) {
  efi_handle gop_intf = efi_locate_protocol(&graphics_output_guid, NULL);
  efi_status status = EFI_SUCCESS;

  if (!gop_intf)
      return -1;

  graphics->max_mode = gop_intf->mode->max_mode;
  graphics->modes = calloc(graphics->max_mode, sizeof(void *));
  if (!graphics->modes)
      return -1;

  for (int i = 0; i < graphics->max_mode; i++) {
      graphics->modes[i] = calloc(1, sizeof graphics->modes[0]);
      if (!graphics->modes[i]) {
          status = EFI_NO_MEMORY;
          goto fail;
      }

      graphics->modes[i]->number = i;
      status = gop_intf->query_mode(gop_intf, i,
                      &graphics->modes[i]->size,
                      &graphics->modes[i]->info);
      if (status != EFI_SUCCESS) {
          free(graphics->modes[i]);
          graphics->modes[i] = NULL;
          goto fail;
      }
  }

  /* this sorts the modes by size, but leaves mode.number intact
  * so that we have a way to reference it to the firmware */
  sort_modes(graphics->modes);

  gop_intf->set_mode(gop_intf, graphics->modes[0]->number);
  set_kernel_params(graphics->modes[0], kernel_params);

  return 0;
fail:
  /* best effort... */
  if (graphics->modes && graphics->modes[0]) {
      gop_intf->set_mode(gop_intf, graphics->modes[0]->number);
      set_kernel_params(graphics->modes[0], kernel_params);
  }
  return -1;
}

This is a simplified version - for more details, check out efigraph.c for the excrutiating details.

set_kernel_params() in turn fills out the data structure we give to the kenrel, which then uses the efifb driver to configure a framebuffer console with the correct resolution and pixel format.

Clearly, there is plenty that can go wrong here. With that in mind, I wrote a tool called modelist.efi to debug some of these problems.

In the bug, I’m told:

With a 1280x1024 capable monitor connected to a *censored* or *censored* in
uEFI mode, the remote video redirection via BMC (*censored*) does not display
anything. The reason is that the efifb driver chooses the VGA mode
1280x1024x32bpp which the video redirection doesn’t support (the *censored*
chip doesn’t support video modes that need more than 4MB video RAM).
See also bug #XXXXXX for the same problem reported in the past for Xorg / mga
driver.

efifb: probing for efifb
efifb: framebuffer at 0x90000000, mapped to 0xffffc90011800000, using 8192k,
total 8192k
efifb: mode is 1280x1024x32, linelength=5120, pages=1
efifb: scrolling: redraw
efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
fbcon: EFI VGA (fb0) is primary device
Console: switching to colour frame buffer device 160x64
fb0: EFI VGA frame buffer device

With the knowledge of how the stack works in mind, I know that we need to find out what the firmware is actually returning to the bootloader in order to tell what layer the problem is at, so I ask:

Can you run /boot/efi/EFI/redhat/modelist.efi (from the gnu-efi package) and
show us the output?

And the response is:

fs0:\EFI\redhat> modelist.efi
GOP reports MaxMode 4
0: 640x480 BGRR pitch 640
1: 800x600 BGRR pitch 800
2: 1024x768 BGRR pitch 1024
3: 1280x1024 BGRR pitch 1280

So this tells me that the firmware is listing 4 video modes, each of which has a 32-bit pixel of the form (blue,green,red,reserved). At this point we know that the firmware is telling us about modes that the hardware cannot support, and efifb cannot correctly support this device until the firmware is fixed.

It’s important to have and use the right tools.

Neutrality Regarding Net Neutrality?

| Comments

The Economist has run an article this week that’s left me quite disappointed. In A tangled web, they make an attempt to explain the question of Net Neutrality without taking sides. In doing so, some critical details of the history of the debate are omitted and biased terms are allowed to stand without serious discussion. This leaves the reader in a position where forming an unbiased understanding of the facts is impossible. The result is a rather more biased viewpoint than I’ve come to expect from The Economist. The article’s major failings are twofold. It forms a broad analogy which doesn’t hold up to scrutiny - that “fast-tracking” and “pay for priority” are the same thing - and fails to appropriately distinguish between backbone “transit” (bandwidth between ISPs) and end-user bandwidth.

Fast tracking, they explain, is the practice of being able to pay more money to an ISP to get a faster internet connection. “Pay for priority”, in contrast, is a term used by service providers to describe selling ad-hoc services to a consumer. The problem with the latter is in the details. To implement “pay for priority”, they must limit bandwidth on a per-service basis for other services - either at the transit level or at routers that service individual consumer connections. This necessarily means interfering with network connections, stifling connections that don’t originate at their services in order to provide services to their customers faster. There are several methods which can be utilized for this, ranging from simply providing insufficient transit bandwidth to actively tampering with user’s connections.

The transit method requires that the ISP is also fulfilling the role as content provider, which is the normal case in practice. This method is to simply have much more bandwidth between the ISP’s content servers and the customer than the amount of bandwidth customers demand to other content providers, or to artificially restrict bandwidth between the ISP customers and outside content. This is what they refer to as “reasonable network management”, but it’s anything but reasonable. Under this scenario, an ISP customer buys (for example) 20Mb/s of download bandwidth. But what the customer actually receives is 20Mb/s of download bandwidth from content their ISP hosts, and severely limited bandwidth to other content providers. This is essentially what Comcast wants to do with Netflix bandwidth - they want Netflix’s ISP, Level 3, to pay extra to send data to Comcast’s internet customers, or Comcast will limit their customers’ access to Netflix’s streaming video data.

What the cable companies want agency to do concerning their ISP customers, however, is not limited to merely extortive practices with other content providers’ data. Nor have they attempted to charge their ISP customers more in order to provide more bandwidth to outside content. When Comcast decided that bittorrent was in competition with their TV and movie content interests, for example, they didn’t simply block all bittorrent traffic and demand a fee from their ISP customers for access to the service. In this case there was no individual company from which to extract fees, since bittorrent is a so-called peer-to-peer service, where traffic originates at individual ISP customers both inside and outside of Comcast’s network. Instead, they intentionally modified their ISP customers’ bittorrent traffic by introducing fake packets which reset their customers’ connections, dramatically increasing the protocol overhead for any bittorrent users to the point where the service was not usable. The customer saw what was a technically functioning service, but with performance so degraded that nobody would want to use it. This is what “pay for priority” means in practice. In short, it’s institutionalized fraud: in theory the consumer is paying for bandwidth, a commodity, from an ISP, but in practice the ISP has control over what the customer can use that bandwidth for - thus relieving it of commodity status.

While the article’s conclusion - that lack of competition among service providers is a large problem which must be addressed - is correct, the authors fail to understand that allowing service providers to discriminate among services being carried through the connections leaves an Internet where price discrimination for access to bandwidth is irrelevant.