Introduction
As I was trying to hack through the Linux source code, I found that there
was not enough material explaining the way the source code is structured.
I tried to understand the code sequence by tracing my way through the
boot sequence, part of it has been reproduced here for those who are
interested.
It is no way complete (for I have not yet made my way through the
entire code sequence) and neither is it guaranteed to be correct as
I may be mistaken at some places in my understanding of the code.
Send in your comments to
kvs@csa.iisc.ernet.in, especially if you do notice any goof
ups.
A few things are in order before I start:
- some knowledge of the 386/486 architecture and the PC hardware
is essential to understand parts of the code. I would recommend
that you have a manual handy when reading the code.
- This description is specific to Linux 1.2.3. I had this version
installed on my machine and did not find the need to keep up with
the latest updates, so bear with me.
- Most of the info is from the comments that I found along the way and
some of it I have put together.
- In all cases I will use the name of the file where the code is
contained for some action.
- As far as convention goes, I have used emphasized mode
when referring to routines and files, and typewriter mode
when referring to macros and variables in the code.
Boot up part done by a PC.
On powering on the processor tests itself and proceeds to perform
what is known as POST(Power On Self Test). It sets up some interrupt
routines into the BIOS, and then tries to read sector 0 of either
the floppy drive (if there is one) or the hard disk. It loads sector
0 into a fixed location in memory and passes control to this code.
Sector 0 or the bootsector contains the code that is used to
bootstrap the kernel.
Linux Boot Sequence
- linux/arch/i386/boot/bootsect.S
- Resides in the boot sector.
- Initially boot sector is loaded at 0x7c0 and control
is passed to it.
- Move the boot sector to INITSEG(=0x90000) {see figure}
- Set up stack at 0x9000:0x4000-12
The 12 bytes are used for storing drive parameters.
- Copy the drive parameters into the above mentioned reserved location.
- Load setup sectors from disk directly after the boot block.
- Get the number of sectors/track info by probing with different
#sectors.
This is done as there is no system call which gives the number
of sectors/track info.
- Print the message:
Loading
- Load system into SYSSEG(=0x10000).
This is done by the read_it routine which then calls read_track.
The "......" which is printed during the bootup time is printed
by the read_track routine.
- Check the data at the end of the bootblock to see if the Root
device has been defined.
In case it has not been defined, set defaults and store it back.
- Jump to the SETUP code which has been loaded at SETUPSEG
(=0x90200) just after the boot block.
Memory map
0x07c00 | | - original boot sector loaded by
| | BIOS(256 words)
|-------------|
0x10000 | | - SYSSEG, system is loaded here.
|-------------|
0x20000 | |
|-------------|
0x30000 | |
|-------------|
z z
|-------------|
0x80000 | |
|-------------| - INITSEG, Boot sector is moved here
0x90000 |-------------| - setup sectors imm after boot block
| |
|_____________| - 0x9000:0x4000-12, Stack
|-------------| - drive parameters
| |
|-------------|
| |
|-------------|
NOTE: Max system size can be 8*65536 - 4096 bytes.
linux/arch/i386/boot/setup.S
- Some code which says "BOOTLIN depends on this being done early"
Can't figure out what this means
- Check the signature at the end of setup.
Signature should be AA55 5A5A.
In case of Bad signature, copy again from where the original SETUP code
could be and try again.
In case of a failure again, print a message and enter an infinite loop.
- Get the memory size and set the keyboard repeat rate to maximum.
- Check for EGA/VGA and some other? config parameters.
- Get hd0 and hd1 parameters From where? and store it in
INITSEG.
- Check if there is a disk 1.
In case the first disk is absent clear the data corresponding to
the config parameters of the first disk.
- Check if there is a PS/2 mouse.
- Ignore interrupts (cli) and disable NMI for bootup.
- Copy the system to the final location i.e from 0x1000 - 0x90000 below 640K
- Load the segment descriptor registers
- idt (interrupt descriptor table) is loaded with 0x000000
- meaning idt_base = 0x0000, idt_limit = 0x00
- gdt (global descriptor table) is loaded with 0x09(512+gdt)80
- which means gdt_limit = 0x80 => 256 gdt_base = 0x9xxxx+512.
Why add 512?
- Enable A20
- Ensure that coprocessor is properly reset. Some delays are inserted
here and I don't really know why?
- Setup the interrupts.
- IBM has used 0x08-0x0f for BIOS.
- Reprogram the 8259's to use int 0x20-0x2f
- 8259-1 uses interrupts 0x20-0x27
- 8259-2 uses interrupts 0x28-0x2f
- and then mask everything off.
- Set the protected mode bit, and jump to the kernel.
Since we are now in protected mode, the jump is made to
KERNEL_CS:0x1000
Remember that 0x1000 was the location to which the kernel was earlier
moved to.
linux/arch/i386/boot/compressed/head.S:startup_32
- Check if A20 is enabled.
- Reset the NT flag, Clear BSS.
- Call decompress_kernel
At this point the kernel resides in the absolute address
0x00001000, decompressing to moves the kernel to a different
location. The first page 0-0x1000 is left free. 0x1000 onwards
will be use for the page directory.
linux/arch/i386/compressed/misc.c:decompress_kernel
- uncompress the kernel and puts it in virtual address 0x1000 0000(=1MB).
linux/arch/i386/boot/compressed/head.S:startup_32
- Initialize registers and clear BSS.
- call setup_idt
- sets up the interrupt descriptor table with 256 interrupt
gates all of which point to the ignore_int routine.
The ignore_int routine prints "Unknown Interrupt" message.
- Check if A20 is enabled and initialize EFLAGS.
- Copy bootup parameters out of the way into empty_zero_page
as illustrated in the memory map figure #2.
- Check if 386/486 and get the type of the processor.
- Check for co-processor.
- call setup_paging
- Clear both the swapper_pg_dir and pg0 areas.
swapper_pg_dir -> page directory
pg0 -> kernel page table
- Make an entry from the pg_dir to setup pg0 as the page table
for the kernel.
- The kernel is then mapped at the virtual addresses
- 0x0000 0000 : an identical mapping used when accessing
addresses within the kernel.
- 0xc000 0000 : to map the kernel into the virtual address
space of any other process.
- Fill up the page table entries for the kernel in pg0
- Make cr3 point to the swapper_pg_dir(the page directory)
and mark paging begin.
- Load the idtr and gdtr registers to new tables.
- Clear the ldt register.
- Call start_kernel(0,0,0).
_________________ 0x0000 (Unused)
| |
|---------------| 0x1000 (swapper_pg_dir)
| | 0x1c00 & 0x1000 contain entries for kernel
|---------------| 0x2000 (pg0)
| |
|---------------| 0x3000 (empty_bad_page)
| |
|---------------| 0x4000 (empty_bad_page_table)
| |
|---------------| 0x5000 (empty_zero_page)
|_______________| - 2KB Bootup params
| | - 2KB Command line args
|---------------| 0x6000 (floppy_track_buffer)
| |
Memory map 2
linux/init/main.c:start_kernel
linux/arch/i386/kernel/setup.c:setup_arch
- Get Root device, drive info, screen info, aux device
- Initialize memory for init_task i.e task 0.
- Get the command line parameters and set the end & beginning
of memory.
- Allocate I/O space addresses for dma, timer, rtc
This is done using calls to request_region, with the device
name, and the address range at which this device is mapped.
linux/init/main.c:start_kernel
linux/arch/i386/mm/init.c:paging_init
- check if there is a page table associated with the kernel,
otherwise allocate space to hold a page table and then
map the memory into the page table.
Invalidate the page directory register.
call free_area_init
linux/mm/swap.c:free_area_init
- Set the min number of pages that should be free at any
time. The value of this cannot be < 16 (arbitrary).
- call init_swap_cache
- Align memory_start
- The swap_cache contains a pointer for each page in system.
Reserve enough memory to hold these pointers and appropriately
modify memory_start. Also reset these pointers to 0.
- Reserve memory for a memory map (a pointer for every page) and
set all these to MAP_PAGE_RESERVED. Appropriately modify
start_mem.
- It seems that linux maps free pages using a buddy system.
The code here seems to allocate bitmaps for free_area_list (there
are 6 of these) and for each case the sizeof the bitmap is
halved. Have to inspect the code to confirm that it actually
uses a buddy system. All bitmaps are initially set to 0.
linux/arch/i386/mm/init.c:paging_init
linux/init/main.c:start_kernel
linux/arch/i386/kernel/traps.c:trap_init
- set trap gates for page fault, double fault, coprocess, for
all the faults and call gates for single_step, bounds and overflow
- set system entry point to int 0x80
- set tss and ldt descriptor and initialize all descriptors
in the global descriptor table to 0. There are two descriptors
for each process in the gdt -- one for tss and one for ldt.
- Load the ldt and tss registers with 0.
linux/init/main.c:start_kernel
linux/arch/i386/kernel/irq.c:init_IRQ
- Program the timer chip to interrupt every 10ms.
- Set the timer interrupt vector.
- Set all the interrupts from PIC1 to bad_interrupt.
- Allocate IRQ2 for cascade and IRQ13 for math_error.
- Allocate I/O space addresses for PIC1(0x20-0x40) and PIC2(0xa0-0xc0)
linux/init/main.c:start_kernel
linux/kernel/sched.c:sched_init
- Set the bottom half handlers for timer, tqueue and immediate
- Allocate through request_irq, TIMER_IRQ(IRQ 0) for the
timer interrupt handler -- do_timer.
request_irq makes an entry in its internal tables to have
the do_timer routine called every time an interrupt arrives
or IRQ 0.
- Enable the bottom half handlers
linux/init/main.c:start_kernel
- call parse_options to parse command line options.
- call init_modules
linux/kernel/module.c
- figure out the #symbols in the kernel and setup the #entries
field in the kernel symbol table.
- set the state of the kernel module to RUNNING.
linux/init/main.c:start_kernel
- if kernel profiling is turned on, then reserve memory to hold
the profiling information.
- call console_init
linux/drivers/char/tty.c:console_init
- Initialize all ldisciplines to 0
- Register a line discipline for N_TTY(Tty) by making a call to
tty_register_ldisc
- Clear the standard termios structure.
- Initialize the iflag, oflag, cflag and
lflag of the standard
termios structure. Initial values are as follows:
- iflag -> ICRNL+IXON
- oflag -> OPOST+ONLCR
- cflag -> B38400+CS8+CREAD
- lflag ->
ISIG+ICANON+ECHO+ECHOE+ECHOK+ECHOKE+ECHOCTL+IEXTEN
For meaning of the initialized values see man stty.
- call con_init
linux/drivers/char/console.c:con_init
- Initialize the console_driver (tty_driver struct)
for the console.
The console_driver structure contains functions to open,close
read/ioctl the console device.
- call tty_register_driver
linux/drivers/char/tty_io.c:tty_register_driver
- calls `linux/fs/devices.c:register_chrdev' to register the device as
a character device. register_chrdev performs sanity checks to see if
the major device number is within the correct range and then associate
a set of file operations with the device. It also checks to see
if the device has already been registered.
**The reason why the console driver has to be registered with the file
system is because all devices are accessed via the file system, so
the file system should know which routines to call, when requests
are made to this device.
- add the console driver to the kernel list of tty drivers.
linux/drivers/char/console.c:con_init
- call con_setsize to set the default number of rows and columns on the
console.
- set a timer to blank out the screen on expiry
- Check type of the display (monochrome/EGA/VGA) and depending
on display type reserve addresses in the I/O address space by
calling request_region with appropriate values.
- Initialize virtual consoles for MIN_NR_CONSOLES (1) by allocating
meory and moving start_mem above that area. Initialize
the vc struct fields by calling vc_init. vc_init also
does a few other things which I have not been able to figure
out as yet
- Set the current foreground console, initialize the cursor position,
clear the screen to the end and print
Console EGA ...80x24...
- call register_console
linux/kernel/printk.c:register_console
- called during console initialization time to initialize the console
driver printing function with the printk routine. This allows
all printk's of kernel to print directly to the console.
Also prints all kernel generated messages thru printk which occured
before the console driver was initialized.
linux/drivers/char/console.c:con_init
linux/drivers/char/tty.c:console_init
linux/init/main.c:start_kernel
linux/arch/i386/kernel/bios32.c:bios32_init
- Checks for a valid BIOS signature from 0xe000 to 0xffff.
Flag an error if more than one entry is found.
- call pci_biosinit Haven't figured out how this works as yet.
- call probe_pci
linux/init/main.c:start_kernel
linux/mm/kmalloc.c:kmalloc_init
- The total amount of memory available for kmalloc, is 128K,
and is managed by using an array of structures called sizes.
Memory is managed in powers of 2 called order. The kmalloc_init() routine
performs some sanity checking on this structure to determine
if in each order the sum of the available memory + data_structure
with each allocated block < total kmallocable memory.
System will panic if any such inconsistency is found.
linux/init/main.c:start_kernel
- call calibrate_delay
- Computes the BogoMips of the machine. This is computed by trying
to estimate the number of iterations of a loop that can be
executed in 1s. Since the loop which is executed contains
2 instructions/iteration, divinding loops_per_sec/500000
gives the BogoMips rating.
- call chr_dev_init
linux/drivers/char/mem.c:chr_dev_init
- Register memory as a character device with the file system,
using register_chrdev
- call tty_init
linux/drivers/char/tty_io.c:tty_init
- First check to see if the size of the tty_structure is > PAGE_SIZE.
What purpose does the tty_struct serve?
- Register tty and cua(AUX device) devices with the file system using
register_chrdev
- call kbd_init
linux/drivers/char/keyboard.c:kbd_init
- Initialize keyboard_structures. (One for each virtual console).
kbd_struct is defined in linux/drivers/char/kbd_kern.h, and
seems to have some fields for setting LED etc. Don't know
what it is exactly used for.
- Set the bottom half handler of the keyboard device to
kbd_bh
- Grab the IRQ for keyboard using a call to request_irq
- Reserve I/O space addresses for keyboard using
request_region
- There is some special processing done here for if the machine
is an alpha, which I have conveniently omitted to understand.
- Enable the keyboard bottom half handler.
linux/drivers/char/tty_io.c:tty_init
linux/drivers/char/serial.c:rs_init
- rs_init is used to initialize tty devices connected on the
serial port using the RS232C connector.
- Setup and enable a bottom half handler for the serial device.
- Setup a timer.
- If auto configuring of IRQ is turned on, check if the system is
generating any wild interrupts by calling
check_wild_interrupts.
This routine returns a bitmap of IRQ's which generate wild interrupts.
Such IRQ's are ignored while autoprobing for the serial port
IRQ is done at a later stage.
- An array of IRQ_ports and IRQ_timeouts is initialized to 0. The
IRQ_ports seems to be an array of per IRQ pointers to the
UART structures. Have to still figure out what the timeouts are for
- call show_serial_version to print the message
Serial driver 4.11 ....
- Initialize the serial_driver structure for the ttyS and the
callout_device structure for cua. The ttyS device is for attaching
ttys/slip/mouse, while the cua device is used for modems.
- Register the serial_driver and the callout_driver with the other
tty drivers using tty_register_driver. Similar to how the console
driver was registered earlier.
- Information about each serial line is stored in a table of
async_struct. Some fields of this table -- rs_table -- are
statically initialized. The remaining fields are now initialized
and a call to autoconfig is made with the port address of the tty
line.
- first attempts to check for existence of the serial port.
- If that succeeds it tries the loopback test (provided the
flag for that is set).
- calls do_auto_irq to get the IRQ number associated with the
chip. This is done by grabbing all the unassigned IRQs, and setting
each of the these to rs_probe. rs_probe when executed will
set a flag and the IRQ number which triggered it off. Then
make two attempts to generate a serial port interrupt and
identify the IRQ line on which the interrupt was received.
If the IRQ identified in both cases match, a positive
identification has been done, so free all the interrupts
that were grabbed(free_all_interrupts).
- Probe and determine the UART chip used.
- Reserve I/O space addresses for the serial device using
request_region
- If autoconfig succeeded in determining the chip, print the message
ttyS at addr(irq)....
linux/drivers/char/tty_io.c:tty_init
- call cyc_init if cyclom card is present.
linux/drivers/char/cyclades.c:cyc_init
- Most of the stuff is similar to that of the serial driver
described above.
- Show version of the driver
- Initialize cy_serial_driver and cy_callout driver and register
them with the list of tty drivers using tty_register_driver.
- Set up and enable the bottom half handler do_cyclades_bh.
- The IRQ_cards structure is initialized to 0. This is a per IRQ
array of pointers to the cyclades_card structure which maps
an IRQ number to the corresponding card.
- Scan through the table cy_card which contains all possible base
addresses of the card along with the corresponding IRQ number,
number of chips and the line number of the first channel on the
card. The base address field alone is statically initialized.
On detection of a card, the remaining fields are filled up.
- The existence and number of chips on the card is determined by
making a call to cyc_init_card. It seems that the cyclades
card is memory mapped rather than I/O mapped.
- If autoprobing of IRQs is turned on, use do_auto_irq to determine,
the IRQ used by the card.
If an IRQ is found bind it to the card using request_irq
Also initialize the corresponding entry of the IRQ_cards array
to point to the cyclades_card structure.
- Since each card can have multiple ports associated with it, the
state of each of the ports has to be initialized.
- All remaining ports are initialized to 0.
linux/drivers/char/tty_io.c:tty_init
linux/drivers/char/pty.c:pty_init
- initialize the pty_driver and the
pty_slave_driver structures
and register them with the kernel list of tty drivers using
tty_register_driver routine
linux/drivers/char/tty_io.c:tty_init
linux/drivers/char/vc_screen.c:vcs_init
- register the file operations structure for handling virtual consoles
with register_chrdev
linux/drivers/char/tty_io.c:tty_init
linux/drivers/char/mem.c:chr_dev_init
linux/drivers/char/lp.c:lp_init
- Register the file operations associated with the printer with
the kernel file system using register_chrdev.
- The lp_table structure contains all possible port values and
addresses that can be taken by the line printer.
- Use the base address as specified in the lp_table structure and
check if the address range required is free. This is done by
making a call to check_region with the address range as arguments.
check_region goes through the list of I/O address
ranges which have
reserved by other drivers in the kernel(using request_region).
- If the default address range is free, then probe the associated
port by writing to it and the reading back the value after some
delay.
- If the probe succeeded, then mark the existence of the port by
making a corresponding entry in the lp_table. Then reset the
printer, reserve the I/O address range used by the printer
with a call to request_region. Finally print the message
lp. at ....
- There seems to be no probing for the IRQ to be used with the line
printer driver. The defaults in the lp_table assume that no IRQs
are used with the lp_table and this does not seem to get modified
anywhere. Is this right?
linux/drivers/char/mem.c:chr_dev_init
linux/drivers/char/mouse.c:mouse_init
- call bus_mouse_init, if configured for a bus mouse
linux/drivers/char/busmouse.c:chr_dev_init
- Configure the mouse port to check existence.
- Write a signature byte to the signature port, delay for
some time and then read it back. If the byte read from
the port is not the same as what was written, return
back reporting absence of mouse.
- Now configure it to the default values and set up the mouse
driver.
- Print the message
Logitech Bus Mouse ....
linux/drivers/char/mouse.c:mouse_init
- call psaux_init, if configured for a PS Mouse or a 82710 mouse.
linux/drivers/char/psaux.c:psaux_init
- check for 82C710 type of pointing device by calling
probe_qp
- As an aside, the qp in probe_qp seems to be due to quickport. Some
explanation as to why references within the file have
been changed from quickport to 82C710.
- write some config information to the device address.
The code write 0x55 and 0xAA(0xAA=~0x55). Then addresses
the chip and writes 0xe4 & ~0xe4=0x1b. 0xe4=390/4 where
390 is the config address.
- Then it tries reading back the config address and if it
is not 0xe4, then the probe has failed.
- Else initializes qp_data and qp_status and closes the chip
config mode.
- The details of why the above sequence was done is
chip specific, and I don't really know what it means. I
just copied it out from the comments with the code.
- print the message.
82C710 at .....
- Initialize psaux_fops read and write routines.
- call poll_qp_status to check if the receive and transmit
buffer is empty.
- All the initialization for the 82C710 type device is over.
Now test for a PS/2 type device.
- Check if the aux_device_present variable is set to 0xaa.
This value is initialized in setup_arch
- In case the device is absent return back, otherwise
print the message
PS/2 auxiliary ....
poll the status of the device.
- Reserve some memory to hold pointers to a queue.
- If aux device detected, the initialize the aux device.
linux/drivers/char/mouse.c:mouse_init
- call ms_bus_mouse_init, if configured for a Microsoft Bus mouse.
linux/drivers/char/msbusmouse.c:ms_bus_mouse_init
linux/drivers/char/mouse.c:mouse_init
- call atixl_busmouse_init, if configured for a ATI-XL busmouse.
linux/drivers/char/atixlmouse.c:atixl_busmouse_init
linux/drivers/char/mouse.c:mouse_init
- Register the mouse driver with the filesystem using
register_chrdev
linux/drivers/char/mem.c:chr_dev_init
- call soundcard_init, if configured to detect the soundcard.
linux/drivers/sound/soundcard.c:soundcard_init
- Register the file operations structure for the sound card
with the file system using register_chrdev
- Set a flag soundcard_configured to indicate that
the driver for the soundcard has been installed.
- There is a lot more stuff here, but I am ignoring it
at present as I don't have a sound card. Later when I find
time, Will complete this section
linux/drivers/char/mem.c:chr_dev_init
linux/drivers/char/tpqic02.c:qic02_tape_init
linux/drivers/char/mem.c:chr_dev_init
- If FTAPE is configured, allocate NR_FTAPE_BUFFERS of each
32KB aligned and print the message
ftape: allocated .....
linux/init/main.c:start_kernel
linux/drivers/block/ll_rw_blk.c:blk_dev_init
- The kernel maintains a table of request structures for all
the block devices all_requests. Each of the request
structures, contains all information about the request such
as the device number, the command, the number of sectors,
the address, buffer head etc.
- The all_requests table is first initialized by making
all device field of all the structures = -1, indicating an inactive
entry.
- ro_bits is then cleared. ro_bits is a bitmap for
used to make a device readonly.
- Now comes the part where each device is detected and the
appropriate driver initialized.
- call hd_init if CONFIG_BLK_DEV_HD is set.
linux/drivers/block/hd.c:hd_init
- Register the file operations for the hard disk device with the
kernel file system file operations using register_blkdev.
register_blkdev registers the file operations with the
file system depending on the MAJOR device number of the device.
In case the major device number of the device is 0, it triesa
to register the device with the highest available device number
upto MAX_BLKDEV.
- Set up the request function for this device by making
blk_dev[HD_MAJOR].request_fn = do_hd_request
- Set the number of sectors to read ahead for the hard disk to 8.
- There is some stuff about hd_gendisk.next..., which
needs some figuring out.
- Set the timer routine for the hard disk.
linux/driver/block/ll_rw_blk.c:blk_dev_init
- call ide_init if configured for ide drivers.
linux/driver/block/ide.c:ide_init
- The ide driver can support two interfaces, and on each of these
interfaces upto MAX_DRIVES(=2). Each of these drives could have
multiple partitions, specified by the bits in the
minor device number which are reserved for this purpose --
PARTN_BITS(=6). All device information is stored in a two
dimensional table ide_dev indexed by the interface
and the drive number.
The initialization sequence described below has to be
carried out for each of the hardware interfaces.
- call init_ide_data
- For each logical drive (partition) in this interface,
initialize the blocksize (ide_blksizes) to 1K.
- Set the default blocksize for the device.
- Initialize the non-geometry fields of ide_dev.
There is comment here that ide_setup runs
before this routine, but have not been able to trace
the point at which the call to ide_setup is made.
- For hardware interface 0, then call probe_cmos_for_drives to
detect the presence of drives.
- Read from the CMOS address 0x12. The state of each
nibble(=0xf) indicates the presence of the disk.
- The disk geometry can now be determined from the BIOS,
so fields of ide_dev[0].drive number can be
initialized. Sets dev->present for the detected
drives.
Recall that as one of the first steps in the
setup_arch routine, we got the disk parameters and
saved it. That is now used for the above initialization.
CMOS and BIOS do not contain information about the drives
connected to the second hardware interface, and these have to be
detected by probing. Therefore dev->present will not
be set for the drives connected on the second ide interface.
- call probe_for_drives to identify all drives on this interface.
linux/drivers/block/ide.c:probe_for_drives
- Check if the range of I/O addresses used by the IDE driver
is free. If it is not free report an error and return back.
- The remaining section of the code, probes for the devices,
initializes them and then reserves I/O addresses.
- First allow interrupts, this is required in identifying the IRQ.
- call probe_for_drive for the first drive on the interface.
linux/drivers/block/ide.c:probe_for_drive
- If dont_probe is set for this device, then return back.
- call do_probe with the ide device structure and ask it to
identify itself
- First checks to see if the probed device is a CDROM the
command is a WIN_IDENTIFY in which case it
returns back. Since CDROMS use the ATAPI interface
use WIN_PIDENTIFY instead.
- Select the target drive, wait for 10ms and then read from
the drive again. If the value returned by the read is not the
same as what was written out, and the device structure
does not indicate the presence of the device, then return back
with an error value of 3 indicating bad status from device.
The OUT_BYTE and IN_BYTE macros used here
automatically compute the effective I/O port address depending
on the port address provided to the macro and the number of
the ide interface used.
- If the device is ready and not busy or is present or the
command is WIN_PIDENTIFY make two attempts to
identify the device type by calling try_to_identify
- Disable device from generating an interrupt
- if PROBE_FOR_IRQS is defined, then first check if an
IRQ has already been probed for and located for the current
interface, then grab all the available IRQs, and enable the
device IRQ for the device.
- Wait for 10ms.
- Read with both the HD_STATUS and HD_ALTSTATUS
commands and check if they are the same for all the fields.
If they differ, then the drive is an Old Seagate drive
(so says the comment), use the HD_STATUS command.
The difference between the two commands is that
HD_STATUS will clear the IRQ field.
- Send a command to ask for the drive ID and set a time out.
The timeout is 15s for a hard drive an 0.5s for a CDROM.
- Wait till either the timeout occurs (in which case turn
off the IRQ probing and return with an error value of 1) or
till the drive status stops being BUSY.
- Check the status of the last operation to see if any error
occured, in which case, return with an error value of 2.
- If no error occured call do_identify to read the drive
identification into internal tables.
- Set return value = 0, indicating successful identification of
drive.
- If IRQ probing was turned on, then turn it off using
probe_irq_off,which returns the IRQ number which
generated the interrupt. Multiple IRQs are indicated by
a negative value for the IRQ number and 0 indicates failure.
In case of successful probing of IRQ, initialize the IRQ
number for the current interface, otherwise indicate failure
and print a message.
- If try_to_identify fails twice in succession, then
print the status of the device and a message indicating failure.
- Disable the device irq,wait for 10ms and ensure that drive irq is
clear by reading the device status.
- If the currently selected drive on the interface is the second
drive, then reset it to the first, disable the irq, wait for
10ms and return with the error code.
- If do_probe failed the last time, use it with
WIN_PIDENTIFY to detect a CDROM drive.
- If drive still not detected return with a value 0, indicating
unsuccessful probe.
- If the id field is NULL, print an error message indicating presence
of non-IDE device.
- Indicate presence of device and return.
- If the device type is a CDROM, call cdrom_setup to set up the drive
configuration.
- If device is disk then check if the #heads lies within the correct
range otherwise print an error message.
- return indicating successful probe.
linux/drivers/block/ide.c:probe_for_drives
- If probe_for_drive returned successfully for the first
drive, or it there is a second drive present on the interface, probe
for the second drive using probe_for_drive.
- Clear any IRQs.
- If a drive has been detected on this interface, then reserve I/O
addresses for the interface by making a call to
request_region.
- Restore the flags which were saved earlier befor allowing interrupts.
linux/drivers/block/ide.c:ide_init
- Now setup the generic hard disk structure. First comes the number of
devices attached to each of the interfaces.
- Check if the IRQs used by the two interfaces are the same and if
option for sharing the IRQs has been turned on, then set
sharing_single_irq. Otherwise print an error message and
return.
- Check if the second interface uses IRQ 14, which clashes with
the IRQ # used by the old harddisk driver. So print an error
message and return.
- For each of the interfaces, the devices, request functions and irqs
have to be registered.
- First setup the IRQ handler through setup_irq which in turn
calls register_irq to register the handler for the irq.
In case sharing of irqs is required a single handler is used,
otherwise two handlers have to be installed.
- Next register the file operations on the device with the file
system using a call to register_blkdev
- Then setup the routines to be called on expiry of the timer.
- Set up the request functions for the interfaces.
Again if irq is shared, use a common function.
- Finally add the generic disk structure to the kernel list of
generic disk structures pointed to by gendisk_head.
linux/drivers/block/ll_rw_blk.c:blk_dev_init
- call xd_init to initialize XT hard disk driver.
linux/drivers/block/xd.c:xd_init
- Register the file operations for the XT hard disk driver with
the file system using register_blkdev.
- Set up the request function and the read ahead for the device.
- xd_gendisk is the generic disk structure for the XT hard
disk. Add it to the kernel list of generic disk structures.
linux/drivers/block/ll_rw_blk.c:blk_dev_init
- call cdu31a_init if CONFIG_CDU31A is set.
linux/drivers/block/cdu31a.c:cdu31a_init
- Check for the Pro-Audio Spectrum card and initialize it.
- If the Base I/O address of the cd device sony_cd_base_io
is set to 0xffff, then do not attempt initialization of device.
- Base address of 0, indicates autoprobing using the
cdu341a_addresses table which contains the base addresses
etc., but autoprobing for the cdrom has been turned off using a #ifdef
- Any other non-zero value for the base address is valid and such a
value is set up through command line arguments to LILO.
- call get_drive_configuration
linux/drivers/block/cdu31a.c:get_drive_configuration
- Set ip the base address and use it to setup the addresses of
the cdrom registers.
- Read the CDROM status register and check if returns 0xff(-1),
in which case return back with an error code.
- Reset the drive by calling reset_drive.
- Set a time out and wait for the drive to set the ATTENTION
bit in the status indicating that the reset has completed.
Use sony_sleep to wait till either the bit is set or
the timeout occurs. If irq_used is positive, then
sony_sleep uses interrupts, otherwise it sets the
timeout for the current process and call schedule
- call do_sony_cd_cmd
linux/drivers/block/cdu31a.c:do_sony_cd_cmd
- does a CD command that does not involve a data transfer.
- This routine is reentrant and can be called multiple times
from the same process -- controlled by the recursive_call
flag. However, if the calls are initiated from different
processes, all processes except the first are put to sleep.
- call handle_sony_attention
- First checks the CDROM status to get the status and check
if the CDROM has requested attention. If no attention is
requested then returns back with a 0.
- Otherwise clear the attention bit by calling
clear_attention, and read the result register(by
calling read_result_register). This gives an
atten_code which specifies the reason why the drive
requested attention. Depending on the value of attn_code
do some action.
- This routine also keeps track of the number of consecutive
attentions signalled by the CDROM and flags an error message
if this value exceeds a preset bound.
- Set a timeout and sleep till the drive is busy.
- If timeout expires and the drive is still busy, mark the error
message in result_buffer.
- In case of no error in the previous step, initialize the drive.
The initialization is followed by reading some status information
off the drive (get_result).
Not really sure as to what is done here.
- If a timeout occured in the previous read or if the status
information returned an error try the whole init sequence upto
num_retries times.
- Wake up any processes that are sleeping for this routine and
return.
linux/drivers/block/cdu31a.c:get_drive_configuration
linux/drivers/block/cdu31a.c:cdu31a_init
- Set drive_found if the return status from
get_drive_configuration is correct.
- If drive_found is set, then reserve I/O addresses
for the CDROM driver making a call to request_region
- Register the file operations scd_fopsfor the
CDROM driver with the kernel filesystem routines using
register_blkdev
- if irq_used is negative then attempt to probe and
and determine the IRQ by
- call autoirq_setup to capture all free IRQs
- call enable_interrupts which acts as an interrupt
enable command for the chip.
- call reset_drive to reset the drive. This should
generate an interrupt.
- call autoirq_report to identify the IRQ on which
the interrupt occured and free the remaining IRQ.
- call disable_interrupts to disable the CDROM from
generating any interrupt signals.
- call set_drive_params to the mechanical drive parameters.
- If tmp_irq which contains the result of the IRQ probe
contains a valid(positive) value, then set cdu31a_interrupt
as the IRQ handler by making a call to request_irq.
- Print the message
Sony I/F CDROM : .......
- Also determine the capabilities of the CDROM and print them
as they are recognized.
- Set up a request function for this device.
- set the number of read ahead sectors for this device.
- set the default block size to 1KB.
- Reserve some memory to hold the subcode status of the last
operation performed last_sony_subcode.
- Reserve memory (CD_FRAMESIZE_RAW bytes) for the readahead
buffer.
- Reserve memory to hold the table of contents.
- Set disk_changed and return.
linux/drivers/block/ll_rw_blk.c:blk_dev_init
- These are routines to initialize the CDROMS from other
vendors. Right now I am skipping the details. Maybe I will
add it in later.
- call sony535_init if CONFIG_CDU535 is set.
- call mcd_init if CONFIG_MCD is set.
- call aztcd_init if CONFIG_AZTCD is set.
- call floppy_init if CONFIG_BLK_DEV_FD is set.
which in turn calls new_floppy_init
linux/drivers/block/floppy.c:new_floppy_init
- Register the file operations for the floppy driver, with the
file system using register_blkdev.
- The minor device number for the floppy device depends on the
type of the floppy. The number of floppy types supported is
32, so the number of devices of each type can which can exist
is 8. The sizes in #sectors that each of the devices can
support is stored in floppy_type.size. The
floppy_type structure stores information about the
geometry of the floppy, i.e the #heads,#tracks,sectors/track,
etc for each of the floppy types supported and is statically
initialized.
- Initialize the values of blk_size and
blksize_size for the floppy device. These are
globals defined in blkdev.h and have to find out what
they are used for.
- Set up the request function for the floppy to do_fd_request.
- Remove the fd_timeout routine from the kernel list of
timer routines by making a call to del_timer
- call config_types
- Depending on the number of floppy drive controllers, initialize
the I/O address and the other parameters for each of floppy
drive controllers in the structure fdc_state.
- call floppy_grab_irq_and_dma, and if the call fails,
then deregister the floppy driver and exit.
- This routine reserves the Floppy IRQ and the Floppy DMA
channel. If this routine has already been called, then
this routine fails. If either the DMA channel or IRQ is
already reserved by some other device, it returns an error
code of -1.
- It then initializes the drive_state and
write_errors structures for each of the drives.
- Next it resets ? the floppy drive controller and
attempts to get the version of the floppy drive controller
by calling get_fdc_version
- If the initializing fails for the the floppy disk controller,
then reset have_no_fdc.
- Release the IRQ and DMA channels which were reserved earlier.
- If have_no_fdc is 0, then unregister the floppy driver
as a block device.
linux/drivers/block/ll_rw_blk.c:blk_dev_init
- call sbpcd_init if CONFIG_SBPCD is defined.
- if ramdisk_size is positive, then call rd_init
to initialize the ramdisk
linux/drivers/block/ramdisk.c:rd_init
- Register the file operations structure rd_fops with
the file system using register_blkdev.
- Set up do_rd_request as the request function for
the ramdisk device.
- Reserve memory for the ramdisk and initialize the ramdisk to 0.
- Set the blocksize for the ramdisk device.
linux/drivers/block/ll_rw_blk.c:blk_dev_init
linux/init/main.c:start_kernel
call scsi_dev_init if configured to recognize scsi
drivers.
linux/drivers/scsi/scsi.c:scsi_dev_init
- For a general idea of SCSI driver, read the paper by Rik Faith
on writing SCSI drivers.
It would also help to read the SCSI-2 interface specification
document.
A brief explanation about the structures used here which I have
blatantly copied from the source files.
The structures of interest are the Scsi_Host and
the Scsi_Host_Template.
As their names indicate, the purpose of the
Scsi_Host_Template is to provide the interface
specification for each device supported by the kernel in
a device independent manner, while there is a Scsi_Host
structure for each host which is detected during runtime.
These structures contain: usage count(for use with loadable
modules, name of the host, a detect function (which attempts
to determine the number of cards present for this particular
host adapter type.), a release function(for use with loadable
modules),an info function,
- The initialization routines will have to do the following:
- probe to recognize the presence of host adapters
- initialize internal data structures giving details of
each recognized host adapter.
- initialize data structures for each device type supported
by the driver. Though devices may be attached to a host
adapter, if the driver is not configured to recognize
a particular type of device (say CDROMS) then these
devices will not be probed for.
- Each host adapter can support upto 8 devices; the
initialization routines have to probe for the devices, their
types and their parameters and initialize internal data
structures.
- Initialize a few things, such as a loadable flag, memory start
and timer routines.
- call scsi_init
The builtin_scsi_hosts array contains a template for each
configured card.
Each valid entry in this array is scanned and the detect function
is executed to check for the presence of the card.
If a card of the given type is found, then call
scsi_register create a Scsi_Host structure for
the detected host, initialize it from the template for the host
and add it to a list of list of detected hosts
pointed to by scsi_hostlist.
Once all the cards are detected, call the info routine for the
card to get some info, or if the info routine is not defined, then
use the name field of Host_Template to print the information
scsi : ..
scsi : 3 hosts
Then call scsi_make_blocked_list to create a circular
linked list of all the hosts that have their wish_block
field set.
Now, for each configured device type, call
scsi_device_register to register the device template for
the device.
scsi_devicelist will then contain a list of all the
recognized devices type templates.
The device template for a device contains the high level driver
descriptions for the device.
- For each host detected earlier and present in
scsi_hostlist, call scan_scsis to detect all the
scsi devices attached to this host and create a linked list
of the all the devices recognized so far in scsi_devices.
Each host can have upto 8 devices.
A device is identified by sending a TEST UNIT READY command
to the host for each device.
If the resulting status is non 0, then it means either no
device exists or the LUN used is incorrect.
Now send out the INQUIRY command to get the vendor name, type
of the device.
A non zero status value indicates an error => no device.
Otherwise set the device specific parameter values which
the INQUIRY command returns, print the message:
Vendor: ,........ Model: ..
Type: ...
and add the current device to the tail of linked list of
recognized devices.
- print the message
scsi: detected
- For each device template in scsi_devicelist call
the associated init routine.
The initialization routine registers the file_operations
structure for the device type with a call to
register_blkdev.
Allocate memory to hold the rscsi_disks data structure
which contains details of the capacity of the disk, the sector size etc.
The number of rscsi_disks elements is defined by the
max number of devices supported by the disk template.
Initialize some other fields of sd_template, and
sd_gendisk, and also the sector sizes of these
disks.
- For each recognized device in scsi_devices call
the attach routine which sets up the request function
for the device.
For every such attached device, set up a command block queue
of size cmds_perlun.
- Determine the number of sectors to be used for DMA and allocate
memory for these sectors.
- For each device template in scsi_devicelist call the
finish routine.
For disk devices, the finish routine fills up the rscsi_disks
data structure.
At boot time it attempts to spin up the disks by repeatedly sending
the TEST_UNIT_READY command to the device.
After this it sends a READ_CAPACITY command to the disk
to get the disk size in blocks.
If this command fails, default values are used, otherwise the
rscsi_disks structure is loaded with the values read in
from the disk.
Finally set up the maximum number of read ahead sectors supported
on the device.
linux/init/main.c:start_kernel
- call net_dev_init if configured to recognize some
specific network drivers. On my machine this does not do anything.
- call inode_init to initialize the inode table.
linux/fs/inode.c:inode_init
- set the inode hash table to 0, and the first inode to NULL.
linux/init/main.c:start_kernel
- call file_table_init to initialize the file table.
linux/fs/file_table.c:file_table_init
linux/init/main.c:start_kernel
- call name_cache_init to initialize the directory name
cache.
linux/fs/dcache.c:name_cache_init
- The directory cache contains a mapping between directory entries
and inodes. This is maintained in the form of a two level
lru cache. This routine initializes the two level lru cache
and also the hash table into the cache.
linux/init/main.c:start_kernel
- call buffer_init to initialize the buffer cache.
linux/fs/buffer.c:buffer_init
- The following needs to be done in initializing the buffer cache
- A hash table hash_table has to be allocated
and initialized.
- A data structure buffer_pages to mark pages which
have been used by the
buffer cache needs to be allocated and initialized.
- The LRU list for each class of buffer heads needs to be
initialized. Linux maintains 6 LRU lists for different
states in which the buffer cache is in. The states are:
BUF_CLEAN, BUF_UNSHARED, BUF_LOCKED, BUF_LOCKED1,
BUF_DIRTY and BUF_SHARED.
The lru_list data structure is used to maintain
these lists.
- Some buffer cache entries need to be allocated.
The buffer_head data structure contains all the
info about the block to be accessed. The data
field of this structure points to the data area.
Buffer head free lists are free_list with
a different list for each buffer cache data size.
buffersize_index and bufferindex_si are arrays
into which are used to determine the index into free_list
- First determine the number of entries in the hash table
nr_hash. This is determined by the size of physical memory
available in the system.
- Allocate space to hold the hash table and initialize it to NULL.
- Determine the number of physical pages in the system and allocate
space for the buffer_pages data structure. Initialize
all entries of this structure to NULL.
This structure contains entry to a buffer head structure
if the page is used for storing data.
- Mark the LRU list for the BUF_CLEAN list to NULL.
- call grow_buffers to allocate buffer heads and buffer
cache.
linux/fs/buffer.c:grow_buffers
- get the index into the free list
- allocate one page of space to hold the buffer data.
- call create_buffers to create buffer heads to point to
the above allocated data area.
create_buffers breaks up the page of data
allocated into BLOCK_SIZE blocks and for each
such data block allocates a buffer head through a call to
get_unused_buffer_head. Apart from initializing
the other fields of the buffer head, it links the buffer
heads together using the b_this_page field.
- This linked list of buffer heads is attached to the free list.
- The buffer_pages data structure is updated so
that the entry for the page allocated to hold the data
points to the corresponding buffer head structure.
linux/fs/buffer.c:buffer_init
- panic if unable to allocate any buffers.
linux/init/main.c:start_kernel
- call time_init to read the RTC from the CMOS.
- call sock_init to initialize the sockets layer.
linux/net/socket.c:sock_init
- What the initialization routine is expected to do?
- This has to initialize all the socket protocols supported.
- If the inet protocol is supported, then each of the protocol
layers have to be initialized. Every protocol layer should
be made known to the layer immediately above it and the
layer immediately below it.
- If the kernel has been configured to probe for network
devices, it has to recognize the network card, boot up
the card and initialize data structures related to the
card.
- The data structures used are:
- struct proto_ops which for a give protocol
family defines the routines to be used for creating/reading
etc from a socket.
pops is an array of pointers to the protocol
operations indexed by the protocol family.
Upto NPROTO protocol families are supported.
- struct net_proto is a structure that contains
the name of a protocol and the associated initialization
routine for the protocol.
protocols is a statically initializes array of
type struct net_proto which contains the names
and initialization routines of all the protocols for
which the kernel has been configured.
- struct unix_proto_struct contains all necessary
info about a Unix protocol socket.
unix_datas is an array of the above type and
upto a max of NSOCKETS_UNIX sockets are
supported by the unix protocol family.
- struct inet_protocol contains the routines to
handle data coming from a lower layer.
inet_protos is a hash table of available protocols.
- struct proto contains routines which are used
when a packet is moved down from a upper layer to a lower layer.
tcp_prot, udp_prot and raw_prot
contain the routines for the tcp, udp and raw ip protocol
respectively.
- struct packet_type is used to define the
protocol handling routine for incoming packets at the
network device. It contains a packet type field which is
compared with incoming packets and on a match the
associated routine is invoked.
ptype_base is a linked list of all available
packet types on the system.
- struct device contains the definitions, routines
for all network interfaces.
It contains the base address, IRQ number and an
initiliazation routine for each of the interfaces.
dev_base defined in drivers/net/Space.c
is a statically initialized list of all configured
network interfaces.
- Now for the actual sequence of events. First print the
message:
Swansea University Computer Society NET3.019
- Initialize the protocol operations of the protocol families
defined in pops to NULL.
- call proto_init
linux/net/socket.c:proto_init
- For each protocol defined in protocols call the
associated initialization function.
- On my machine this translates to first calling
unix_proto_init.
linux/net/unix/sock.c:unix_proto_init
unix_proto_ops defines the protocol operations for
the unix protocol family. Call sock_register to
register the protocol operations of this family with the socket
layer.
For each socket in unix_datas set the refcnt field
of the socket to 0.
linux/net/socket.c:proto_init
linux/net/inet/af_inet.c:inet_proto_inet
- Print the message:
Swansea University Computer Society TCP/IP for NET3.019
- inet_proto_ops defines the protocol operations for
the INET family. call sock_register to register the
protocol operations with the Socket layer.
- Initialize the inuse, highestinuse and
sock_array fields of the three protocols, tcp, udp
and raw.
- print the message
IP Protocols:
- Register the inet_protocol structure for each of the
these protocols with a lower layer. These structure define a
receive routine which will be called when the lower layer
(IP) recognizes that a packet is meant for it.
protocol.c:inet_add_protocol is used to register the
inet_protocol structure.
For each protocol added print the name of the protocol family.
- call arp_init to setup the arp family.
linux/net/inet/arp.c:arp_init
- This routine registers a packet type for the arp protocol
with the network device so that incoming arp packets are
passed on to the right driver.
- setup arp_packet_type to hold the type field and the
routine for arp packets, and then call dev_add_pack
to add the packet type to the list of know packet types
pointed to by ptype_base.
- set up a timer to check for expiry of arp table entries. On
expiry arp_check_expire is called.
- call register_netdevice_notifier [Have to figure out
why this is used]
linux/net/inet/af_inet.c:inet_proto_init
- call ip_init to register the packet type of the IP
protocol with the network device layer.
also call register_netdevice_notifier within ip_init
[Have to figure out why this is called].
linux/net/socket.c:sock_init
- if the kernel has been configured to probe for a network
device, then call dev_init
linux/net/inet/dev.c:dev_init
- This uses the statically assigned array of struct
devices, dev_base defined in Space.c.
For each configured interface the initialization routine is
defined in this list.
This routine traverses through the list and for each valid
initialization routine calls it.
Here we assume that only the loopback device and an NE2000
card at eth0 exist.
- First call loopback_init
linux/drivers/net/loopback.c
- Fill up device specific parts of struct device
corresponding to the loopback interface. Set the mtu, the
transmit routine, header length, flags, protocol family,
address. Then initialize all the sk_buff_heads to
point to a null circular list, by making a call to
skb_queue_head_init
linux/net/inet/dev.c:dev_init
- call ethif_probe to look for network cards and
initialize them.
linux/drivers/net/Space.c:ethif_probe
- For each configured driver, it calls a probe routine to find
out if the card exists, in which case probes for succeeding
devices are not made.
call ne_probe to check for presence of an NE2000
ethernet card.
linux/drivers/net/ne.c:ne_probe
- The probe checks to see if the device structure explicitly
requests an address to be probed at, in which case it
directly call ne_probe1.
- If no address has been specified, then traverse through
netcard_portlist which contains a list of probable
I/O address for the network device, check by making a call to
check_region if the range of I/O addresses is
available or has been grabbed by another device.
If the address are available, then call ne_probe
with the address range.
linux/drivers/net/ne.c:ne_probe1
- First check to see if there is an 8390 chip and return on not
finding one.
- print the message:
NE*000 ethercard probe at ...:
- Initialize the registers of the card and then read from the
Station Address PROM. Read 16 bytest of data from the SA
PROM. If the wordlength is 2, then we would actually be
getting two copies of the same byte which will be adjusted
later.
- If the wordlength was 2 bytes, put the card into word mode,
and adjust the values read in from the SAProm, so that the
first 16 entries point to the 16 bytes read from the PROM.
Set the values of start_page and stop_page
appropriately depending on the word length.
- The first 6 bytes of SAProm now point to the ethernet address
of the device, read it in and set address of the device to
the value read in. Print the ethernet address on the console.
- An NEx000 card is recognized by SA_prom [14] and [15] ==
0x57 and a cabletron card by SA_prom [0]==[1]==00 and
[2] == 0x1d. Use this info to set the name of the card. If
the values read from the card are neither of the above, then
scan through the bad_clone_list to see if any of the entries
in this list match the values read from the SA_prom. The
bad_clone_list contains the name of the clone and
the entries for the first three bytes of the SA_prom.
- Next the IRQ used by the card has to be recognized, setup
probing of the IRQ by calling autoirq_setup, trigger
a single interrupt and then calling autoirq_report
to report the IRQ number. Print the message:
autoirq is
- Call request_irq to reserve the IRQ for the network
device.
- call request_region to reserve the I/O addresses
used by the card.
- call ethdev_init to initialize the rest of the
device structure and also the 8390 private data.
linux/drivers/net/8390.c:ethdev_init
- Allocate memory to hold the 8390 private data and setup a
pointer from the device structure to this data.
- Setup the pointers for all the device specific routines, such
as hard_start_xmit, open etc.
- call ether_setup
linux/drivers/net/net_init.c:ether_setup
- This routine fills up the fields of the device structure
which are not dependent on the driver, e.g the MTU, the
header length, the broadcast address etc.
linux/drivers/net/ne.c:ne_probe1
- Print the message
.. found at , using IRQ ..
- ethdev_init has already allocated space to hold the
private data for this device structure and filled in some of
the device specific fields. The remaining fields such as
start_page, stop_page, name and the routines to
block input, block ouput are set.
- call NS8390_init to initialize the 8390 chip.
NS8390_init
- Most of the stuff here is directly copied from the comments
in the code.
- Clear the remote byte count registers.
- set to monitor and loopback mode.
- set the transmit page and the receive ring.
- Clear the pending interrupts and mask
- Copy the station address into the 8390 registers and set the
multicast hash bitmap to receive all multicasts.
- Initialize the multicast list to accept-all
- set device state to not busy, and reset the txing flag.
linux/net/socket.c:sock_init
- No the network device has also been initialized. Set up
net_bh as the bottom half network handler.
linux/init/main.c:start_kernel
linux/ipc/util.c:ipc_init
- call sem_init, msg_init and
shm_init to initialize the semaphore, messages and
shared memory data strucures.
linux/ipc/sem.c:sem_init,linux/ipc/msg.c:msg_init,linux/ipc/shm.c:shm_init
- In each of these cases a data structure is defined which
maintains all information about the connection. These data
structures are respectively the semid_ds,msgid_ds and
shmid_ds. An entry is made in an array of pointers to
these data structures for every valid connection.
The initialization routines the entries in all these arrays
to IPC_UNUSED.
INCOMPLETE. Have to finish this sometime