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: OS should execute the `HLT` instruction when it has nothing else to do (be sure to turn on interrupts first). Power-down an Energy Star monitor Spin down an IDE hard disk APM? ACPI? |

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