From:   "Wayne Gibson" <wgibson@speakeasy.net>
To:   Dan Lewis <dlewis@scu.edu>
Date:   Wednesday - February 20, 2002 1:12 PM
Subject:   Re: Fundamentals of Embedded Software

Dr. Lewis,

I want to thank you for your wonderful book. I am enjoying it greatly, and the projects in particular.

I wanted to share with you a problem I discovered, which happens as the program gets larger. The issue is regarding the "real mode" startup code involving the instruction:

   LGDT [gdt_info] ; load GDT register

The instruction is in a .text section while symbol gdt_info is defined in a .data section. The assembler generates a 32-bit offset reference which the linker fills in after assigning the address to gdt_info. When the program gets larger than 64K bytes the address assigned by the linker may be larger than 65535. This is fine at link time, however at run time when this instruction is executed we are still in "real mode", having come out of reset and through the bootstrap loader, and DS has a limit of 65535, resulting in an exception (which we are not prepared to handle). I might mention that the jumps to the labels Check_CPU and Init_CPU appear to have the same issue regarding the CS register.

The simple program at the end of this message demonstrates this. If you make gdt_info a global symbol you can see the offset directly in the link map.

My solution was to place all the real mode startup code into the init-cpu.asm file into the ".start" section, including the gdt_info and gdt structures. While technically this mixes the code and data it should still work since we are using a flat memory model (DS == CS) and the gdt related data is read-only (so it would still work from ROM). I'm sure there are better ways to solve this but this works.

I hope this saves you and your students some future grief.

-- Wayne Gibson

/*
** Demo program.
*/

#include "libepc.h"

/* Initialize some values to for .data section */
char data[64 * 1024] = { 0, 1, 2, 3 };

int main(void)
{
 PutString("Hello world\r\n");
}