OSD Home

Reprogram the 8253 timer chip to generate interrupts at frequency HZ:

        #define HZ      100

	static const unsigned short foo = 1193182L / HZ;

	outportb(0x43, 0x36);	/* channel 0, LSB/MSB, mode 3, binary */
	outportb(0x40, foo & 0xFF);	/* LSB */
	outportb(0x40, foo >> 8);       /* MSB */

Conserving energy: energy star

Discarding run-once (initialization) kernel code and data, using GNU C. This requires paging, and is a 4-step process.

1. Define macros

Discardable code goes into section .dtext of the .o files, instead of .text
Discardable data goes into section .ddata of the .o files, instead of .data
        #define DISCARDABLE_CODE(X)                             \
		X __attribute__((section (".dtext")));		\
								\
		X

	#define	DISCARDABLE_DATA(X)				\
		extern X __attribute__((section (".ddata")));	\
								\
                X

2. Use macros

        #define HZ      100

	DISCARDABLE_CODE(static void init_8253(void))
	{       static const unsigned short foo = (3579545L / 3) / HZ;

		outportb(0x43, 0x36);   /* channel 0, LSB/MSB, mode 3, binary */
		outportb(0x40, foo & 0xFF);     /* LSB */
		outportb(0x40, foo >> 8); }     /* MSB */

	DISCARDABLE_DATA(unsigned char g_boot_logo[]) =
	{
		0xFF, 0xFF, 0xFF /* ... */
        };

3. Write linker script

The contents of the .dtext and .text sections are merged at link time, but separated by page (4K) boundaries; same for .ddata and .data. This separation lets the virtual memory system isolate the discardable code and data and free its memory after it's been used.
        ENTRY(entry)
        LS_Phys = 0x100000; /* 1 meg = load (physical) address */
        LS_Virt = 0xC0000000; /* 3 gig = virtual address */
        SECTIONS
        {   .text LS_Virt : AT(LS_Phys)
            {   code = .; _code = .;
                *(.text)                /* kernel code at 3 gig */
                *(.rodata*)             /* read-only data */
                . = ALIGN(4096);
                d_code = .; _d_code = .;
                *(.dtext)               /* discardable kernel code */
                . = ALIGN(4096); }
            .data : AT(LS_Phys + (LS_Data - LS_Code))
            {   data = .; _data = .;
                *(.data)                /* kernel data */
                . = ALIGN(4096);
                d_data = .; _d_data = .;
                *(.ddata)               /* discardable kernel data */
                . = ALIGN(4096); }
            .bss : AT(LS_Phys + (LS_Bss - LS_Code))
            {   bss = .; _bss = .;
                *(.bss)                 /* kernel BSS */
                *(COMMON)               /* 'common' vars */
                . = ALIGN(4096); }
            end = .; _end = .; }

4. Free the discardable kernel memory after init

        extern char d_code[], data[], d_data[], bss[];

        /* unmap (data - d_code) bytes at virtual address d_code */
        unmap_mem(d_code, data - d_code);
	unmap_mem(d_data, bss - d_data);

Read text-mode screen size from the VGA registers:
        unsigned char _vc_width, _vc_height;

                unsigned short crtc_base_adr, v_disp;
                unsigned char temp, char_ht;

		if((inportb(0x3CC) & 0x01) != 0)
                        crtc_base_adr = 0x3D4; /* color */
                else
                        crtc_base_adr = 0x3B4; /* mono */
        /* vertical scan lines displayed */
                outportb(crtc_base_adr, 0x12);
                v_disp = inportb(crtc_base_adr + 1);
        /* pull in bits b8 and b9 from the dread overflow register */
                outportb(crtc_base_adr, 0x07);
                temp = inportb(crtc_base_adr + 1);
		if((temp & 0x02) != 0)
                        v_disp |= 0x100;
		if((temp & 0x40) != 0)
                        v_disp |= 0x200;
		v_disp++;
        /* scan lines/char */
                outportb(crtc_base_adr, 0x09);
		char_ht = (inportb(crtc_base_adr + 1) & 0x1F) + 1;
        /* vertical resolution in characters is the quotient */
                _vc_height = v_disp / char_ht;
        /* horizontal resolution in characters */
                outportb(crtc_base_adr, 0x01);
                _vc_width = inportb(crtc_base_adr + 1) + 1;
                printf("Screen resolution is %u x %u\n",
                        _vc_width, _vc_height);

File-as-disk using Linux loopback device (or, You Don't Need Mtools):
#!/bin/sh
BLOCKS=1440
FILE=diskette.img
# create zeroed file
dd if=/dev/zero bs=1k count=$BLOCKS of=$FILE
# make Linux treat it as a disk device
losetup /dev/loop0 $FILE
# create FAT12 (DOS) -OR- ext2 (Linux) filesystem
mkdosfs /dev/loop0 $BLOCKS
# mke2fs /dev/loop0 $BLOCKS
# mount the disk-as-file
# mkdir mnt
mount /dev/loop0 mnt

# create directories on mnt, copy/delete/edit files, etc.

# done with the simulated disk
umount mnt
# done with loopback device:
losetup -d /dev/loop0
# configure bochs to use $FILE (diskette.img)
bochs

REPORT BUGS OR ERRORS IN THIS DOCUMENT