riel | ok, welcome to today's evening lecture |
riel | this lecture will be given by William Irwin, who works for IBM in the US |
riel | now, you know I'm a kernel guy .. but the subject of today's lecture is magic for me, too |
riel | William Irwin (wli) will be talking about how machines in the i386 machine boot |
riel | the word booting comes (I think) from bootstrapping, or pulling yourself up by your boots |
riel | a typical maneuvre for cartoon charactors ;) |
wli | Alrighty. |
riel | since I have no idea how this magic procedure would ever work, I guess I'll turn over the channel to wli |
viXard | easy pal ;) |
wli | Well, I want to give the perspective from the kernel as to what is required to make a machine run on i386. |
wli | Now, the i386 is an elaborate architecture, so I can only cover a few aspects of this. |
JALH | hah, elaborate? crap more-ike |
JALH | s/ike/like/ |
wli | And these are largely the aspects required for a kernel to run on any architecture. |
wli | A fairly simplified model of a system booting is the following: |
wli | (1) the kernel is loaded |
wli | (2) the kernel initializes the state of CPU, especially the registers. |
wli | (3) the kernel enables virtual addressing or paging |
wli | (4) the kernel prepares itself to handle exceptions and interrupts |
wli | (5) the kernel initializes parts of the machine so that interrupts (exceptions generated by external devices) are actually sent to it |
wli | (6) discovering devices and initializing them |
wli | (7) loading the initial programs from storage devices and starting up their execution |
wli | There is a lot of material there, and I would like to stay at a basic level, so I would like to stick to steps 1-4, and briefly cover parts about 5. |
wli | On i386, there are also steps even before (1) in many instances. |
JALH | calc:) |
calc | thx |
wli | Before the kernel runs, firmware called a BIOS is the first thing that actually executes on the machine. |
wli | The BIOS in turn loads the bootstrap loader from a storage device using platform-specific ways to access hardware, and begins executing it. |
JALH | bios loads 512 bytes , last 2 bytes of that sector must be 0x55aa or 0xaa55, loads it at 0x7C00 and goes there.. :) |
wli | The bootstrap loader then has to find the kernel, and there are a number of ways they interact. |
wli | First, the bootstrap loader has to know how to find the kernel on the storage devices. |
JALH | oh, the partition table also takes up 64 bytes at the end too |
wli | Linux itself defines a boot protocol and requires itself to be loaded in a particular location. |
calc | with linuxbios all of that could be gotten rid of right? |
calc | that isn't a question for wli btw ;) |
JALH | hm |
JALH | not sure about the boot seq of the actual chip before the bios |
JALH | I think it starts at 0xfff0:0000 |
calc | well the stuff after the bios would be the same no matter what, aiui |
JALH | but linuxbios would have to be able to load doze etc, no? |
erikm | JALH: that's right. but as soon as linuxbios takes over, you can define your own boot process |
asg | I thought it was FFFFFFF0 but who cares |
JALH | ah |
JALH | it could prolly load linux straight then |
wli | The example I would like to present uses the ELF multiboot format for an executive (a program that runs with direct hardware access, but is not an OS) that demonstrates some of the formats and required control register initializations a kernel would have to do. |
calc | the same process esentially would happen but maybe not the same details |
erikm | asg: somewhere high up. in real mode but still with the CS selector mapped in such a way that it can run from that address |
JALH | yeah |
wli | The ELF file format is understood by GRUB, and that is used to control the locations of memory where the kernel is loaded. |
wli | And also to inform GRUB of the kernel's entry point. |
wli | There is an important issue that arises when loading a kernel this way: |
JALH | 0xf000:fff0 |
wli | There is something called an absolute reference, in contrast to a relative reference. |
erikm | JALH: that's the 8086 entry point |
JALH | in 'real' terms |
wli | A relative reference would add an offset to the address of the instruction being executed or a dedicated register. |
JALH | this is for a 486 |
wli | But an absolute reference specifies the entire address as a constant. |
JALH | nothing at startup has really changed between any of the x86 things :/ |
JALH | backwards compatable with 1980... |
wli | The reason why this is an issue is because a virtual address will be much larger than the physical address. |
asg | intel SDM vol 3 section 8.1.4 |
wli | For instance, in Linux, the kernel sees its own machien code above 0xC0000000 |
wli | But the machine code is far below 3GB, just about 1MB. |
erikm | JALH: ok, got it. it's indeed 0xf000:fff0, but with the CS selector mapped at the highest 1MB. first long jump will switch the CPU to "real" real mode |
JALH | huh.. |
wli | There is a way to deal with this using the ELF format, and that involves load memory addresses vs. virtual memory addresses. |
JALH | weird :) |
JALH | ahh |
JALH | I see |
calc | if your entry point is f000:fff0 wouldn't cs be highest 64k ? |
wli | A load memory address is the real address where the program is loaded, and the virtual memory address is where absolute references are generated. |
wli | This requires giving special directives to the linker. |
JALH | yeah |
erikm | calc: eh, yeah. that's what I mean %-) |
wli | An example: |
wli | SECTIONS |
wli | { |
wli | .multiboot 0x100000:AT(0x100000) { *(.multiboot) } |
asg | However, during a hardware reset, the segment |
asg | selector in the CS register is loaded with F000H and the base address is loaded with |
asg | FFFF0000H. The starting address is thus formed by adding the base address to the value in the |
wli | .boot (0x100000+SIZEOF(.multiboot)):AT(0x100000+SIZEOF(.multiboot)) { |
wli | *(.boot) |
wli | } |
wli | .text (0xC0000000 + 0x100000 + SIZEOF(.boot) + SIZEOF(.multiboot)) : |
wli | AT(0x100000 + SIZEOF(.boot)+ SIZEOF(.multiboot) ) |
wli | { *(.text) } |
wli | ... and so on. |
JALH | *nod* |
calc | erikm: heh |
JALH | which I suppose is the ROM |
wli | Before the : the VMA is specified, and after, the LMA is specified. |
wli | Code linked so that the absolute references are above 0xC0000000 can't execute properly until virtual addressing is enabled. |
wli | c010b0a4 T main |
erikm | calc: the 386 is not really the most clean architecture you'd like to learn about... |
wli | This is loaded at 0x10b0a4, but when you try to call main, the code generated attempts to go to the address 0xc010b0a4 |
JALH | it boots straight to C, it's amazing |
wli | This will not work until paging is enabled, and the mapping from the upper 3GB of the address space is enabled. |
calc | erikm: yea :\ |
wli | Is created, rather. |
calc | i think they use a different arch for comp org 2 |
JALH | prolly arm |
wli | Unfortunately, the memory model on i386 is complex. |
wli | First, in order to be able to reference an address, one must reference an address within something called a segment. |
erikm | JALH: ARM can also boot straight to C |
wli | These segments are a backward compatibility feature from Intel machines before the 386. |
wli | A segment specifies a range of memory and permissions on it. It is a memory protection mechanism based on ranges. |
wli | There are segment registers used to control the segment a memory reference uses. |
wli | These don't contain the whole information about the segments permission and range. |
wli | There is a table called the global descriptor table (GDT) that contains the information about the segments. |
erikm | JALH: depending on the amount of initialisation you need to do you could be into C code in about 10 instructions |
wli | The GDT can contain up to 8192 different 64-bit records describing segments. |
JALH | call that booting straight to C? I'm talking it loads and goes to 'main' |
JALH | I wrote a program to print some strings etc over the serial port and then reboot |
JALH | without a single line of asm |
JALH | :) |
calc | nice |
calc | how does it know which file to run? |
asg | bootloader? |
JALH | the prom on the box loads it via tftp |
calc | ok |
wli | The value of an entry in the GDT is computed from the base address of the segment, the size of the segment, and several control flags to specify what kind of segment it is. |
JALH | in ecoff format |
JALH | it does all the dirty work |
wli | It can be a code segment, a data segment, or a stack segment. |
erikm | JALH: I could do that as well, but I'd better copy the stuff from flash to ram and setup a stack |
wli | It can also be read-only. |
JALH | hm, setting up a stack |
asg | wli: but all this GDT stuff is moot because the kernel sets it up then forgets about it |
JALH | that might come in handy ;> |
JALH | hm |
JALH | the kernel sets up several gdt's |
JALH | well, one in the inital bootloader |
JALH | then one in the head.S or something |
wli | Several of the flags control whether the segment is accessible to the kernel or the user, and also have an escape in order to be able to specify things that aren't segments in the GDT. |
wli | asg: Well, this is about what it does and throws away. |
asg | wli: ok :) |
JALH | and in 2.2, each process uses 2 GDT entries |
wli | For instance: |
erikm | asg: I don't have "understanding the linux kernel" at hand, but didn't the GDT contain an entry for each process? |
wli | #define GDT_SEGMENT_PRESENT_FIELD BIT(15) |
wli | #define GDT_SEGMENT_AVAILABLE_FIELD BIT(20) |
wli | #define GDT_SEGMENT_RESERVED_FIELD BIT(21) |
wli | #define GDT_SEGMENT_DEFAULT_FLAG BIT(22) |
wli | #define GDT_SEGMENT_GRANULARITY_FLAG BIT(23) |
JALH | in 2.2 |
JALH | in 2.4 it has 2 entrys for each CPU |
asg | erikm: what JALH said |
JALH | and does soft task switching |
erikm | JALH: *nod* ok, that was the trick |
JALH | it's neat |
JALH | just save a few reg's then swap the stack |
wli | One way to define some segments appropriate for a kernel to execute is: |
JALH | and fake a ret instruction |
wli | #define KERNEL_GDT_ENTRY \ |
wli | ( \ |
wli | GDT_BASE_ADDRESS_ENCODE(0ULL) \ |
wli | | GDT_SEGMENT_LIMIT_ENCODE(~0ULL) \ |
wli | | (((unsigned long long)GDT_SEGMENT_PRESENT_FIELD) << 32)\ |
wli | | (((unsigned long long)GDT_SEGMENT_DEFAULT_FLAG) << 32)\ |
JALH | no |
wli | | (((unsigned long long)GDT_SEGMENT_GRANULARITY_FLAG) << 32)\ |
wli | ) |
JALH | hm, been a while since I looked at the code, took me a few days to figure it out |
JALH | :) |
wli | And then one can do KERNLE_GDT_ENTRY | (GDT_CODE_TYPE << 32) to obtain a code segment or a data segment. |
wli | When a GDT is loaded, the base pointer of the table is not actually stored, but rather a 48-bit record with a base and a length. |
wli | Essentially: |
wli | struct gdt_record |
wli | { |
wli | unsigned short gdt_limit; |
wli | unsigned long gdt_address; |
wli | } __PACKED__; |
wli | Then definitions like: |
wli | { |
wli | GDT_TABLE_SIZE * sizeof(unsigned long long), |
wli | (unsigned long)&global_descriptor_table[0] |
wli | }; |
wli | unsigned long long global_descriptor_table[GDT_TABLE_SIZE] |
wli | { |
wli | 0ULL, |
wli | KERNEL_GDT_CODE_ENTRY, |
wli | KERNEL_GDT_DATA_ENTRY, |
wli | KERNEL_GDT_DATA_ENTRY, |
wli | KERNEL_GDT_DATA_ENTRY, |
wli | }; |
wli | are possible. |
wli | Now, the segments themselves are things that must be initialized properly, but are not regularly used apart from where required. |
riel | manfred: this is the place to ask questions to wli ;) |
wli | But once they are in place, you can begin setting up page tables. |
wli | There are several control registers on x86, and they very densely encode information, generally with bit fields of the registers. |
wli | For instance, there are bits like: |
wli | #define CR0_PAGING_ENABLED BIT(31) |
wli | #define CR0_CACHE_DISABLE BIT(30) |
wli | and |
wli | #define CR4_PHYSICAL_ADDRESS_EXTENSION BIT(5) |
wli | In general, a kernel will want to use a large page size extension in order to give the processor's internal cache for page table entries more room for user programs. |
wli | That is, when fewer pages are needed to ddescribe the same amount of memory, this cache (the TLB) will not need to have as many trasnlations inserted to access kernel memory. |
wli | My demonstration was tested on a less featureful machine, though, so I will show the kernel using ordinary 4KB pages: |
wli | The page table will be 2 levels, and will need to be initialized before the control register is set to the address of the page table . |
wli | there is a top level that describes 4MB regions, and it has 1024 entries. |
wli | And there is an array of 1024 entries below each of those that has any translations, that gives the translations for 4KB regions of memory. |
wli | I set up 16MB starting at 0x00000000 and mapping identically to physical addresses |
wli | And also 16MB starting at 0xC0000000, but that maps to the same 16MB starting at 0x0 |
wli | These are just arrays of unsigned long with parts of an address in the top bits, and control flags in the bottom bits. |
wli | So I use a loop like this: |
wli | ((unsigned long)(&low_page_table_entries[1024U*k])) |
wli | | PAGE_PRESENT_FIELD |
wli | | PAGE_SUPERVISOR_FIELD |
wli | | PAGE_WRITABLE_FIELD; |
wli | ((unsigned long)(&high_page_table_entries[1024U*k])) |
wli | | PAGE_PRESENT_FIELD |
wli | | PAGE_SUPERVISOR_FIELD |
wli | | PAGE_WRITABLE_FIELD; |
wli | } |
wli | To set up the top level. |
wli | On top, this happens: |
wli | On bottom, rather: |
wli | low_page_table_entries[k] |
wli | | PAGE_PRESENT_FIELD |
wli | | PAGE_SUPERVISOR_FIELD |
wli | | PAGE_WRITABLE_FIELD; |
wli | So there are now segments and page tables ready for the kernel to use. |
wli | Special instructions, which no compiler will generate, must be used to set the registers for these, though. |
wli | Special hand-coded assembly, movl $kernel_page_table, %cr3 needs to happen. |
wli | There is also a special instruction just for loading the GDT. |
wli | So I wrote some procedures in assembly, and they do these for me when I call from C: |
wli | write_gdt(&gdt_record); |
wli | boot_write_cr3((unsigned long)kernel_page_table); |
wli | But there is one more step! |
wli | Unless the flag in %cr0 is set, the page tables installed into %cr3 will not be used. |
wli | boot_write_cr0(cr0); |
wli | And now the code linked at virtual addresses can be called. |
wli | -but- |
wli | There is yet another detail, which this example won't need, but something that expects to run user code might: |
wli | There is support for older pre-386 machines' hardware task switching. |
wli | This support gives the special place where all the registers are saved when an exception is taken a segment all its own. |
wli | And because it's a segment, it must be installed in the GDT. |
wli | This is called the Task State Segment (TSS). |
wli | It's a large data structure that has places for all of the user registers, and also places for all the control registers. |
wli | The choice here is to statically allocate one of these data structures, and to install it in the GDT. |
wli | So now, just before write_gdt() is called: |
wli | But the task switching mechanism essentially wraps up an execution context in a TSS structure, and allows you to switch between them by doing a few things, and most importantly, setting the %tr control register. |
wli | This is not usually a desirable thing to use, so one is set up, and largely ignored there after. But it must be set up! |
wli | |
wli | write_tr(&task_segment_selector); |
JALH | wli, you don't /have/ to have a TSS |
wli | Well, it can be ignored perhaps more than I'm ignoring it, true. |
JALH | linux only needs the TSS to do the IOPERM bitmap |
wli | SMP too. |
wli | don't want them dumping state in teh same place |
JALH | eh? why? |
JALH | each processor can just switch stacks, it can all be done via struct task's I think |
JALH | IE, in sw |
wli | Now virtual addressing is enabled, and we can call the code linked at virtual addresses. |
wli | But there is an important caveat: |
wli | One's stack pointer must be a virtual address. |
wli | To handle that, the code right at the entry point does this: |
wli | call initialize_kernel_virtual_addressing |
wli | movl $kernel_stack, %esp |
wli | movl $kernel_stack, %ebp |
wli | call main |
JALH | wli, why ebp? |
wli | before the kernel stack move, we are executing code at: |
wli | 001010ec ? initialize_kernel_virtual_addressing |
wli | and after: |
wli | c010b0a4 T main |
JALH | :) |
wli | The disassembly shows we really are dereferencing an address in the outer space of 3GB: |
wli | 10003e: e8 61 b0 00 c0 call c010b0a4 <main> |
wli | main() simply does debug_write_unsafe("Hello world!\n"); |
wli | and then initialize_machine_state(); |
wli | There are only a couple of things you'd do before starting to interact with devices: |
wli | (1) set yourself up to be able to handle exceptions and interrupts |
wli | (2) actually arrange to have them sent to you |
wli | Now, (1) once again involves a special register pointing to a table. |
wli | This table is called the Interrupt Descriptor Table (IDT) |
wli | Essentially this is a table of function pointers that tell the CPU which function to call when something happens. |
wli | The exceptions or interrupts have numerical codes describing what happened. |
wli | And these codes act as indices into that table of function pointers. |
wli | the problem is that the call doesn't always communicate the number to you! |
wli | There are some exceptions where the code is passed as an argument, but the others are called with no arguments at all. |
wli | The way this is handled is that a whole bunch of small functions are defined, one for each code, that do nothing more than pass the code in to another function that does the real work. |
wli | The ones that have the code already don't need to do much anyway, but the ones that don't know their number and can set it up as an argument to the real function. |
wli | Now, since there are 256 different codes, I resorted to using macros. |
wli | So bear with me: |
wli | #define IDT_EXCEPTION_HANDLER_WITH_CODE(EXCEPTION_CODE, EXCEPTION_HANDLER) \ |
wli | .global idt_entry_##EXCEPTION_CODE ; \ |
wli | .type idt_entry_##EXCEPTION_CODE,@function ; \ |
wli | .align 4 ; \ |
wli | idt_entry_##EXCEPTION_CODE : ; \ |
wli | pushl $(EXCEPTION_HANDLER) ; \ |
wli | jmp raw_synchronous_exception_handler |
wli | There is actually something else going on, too. |
wli | jmp raw_synchronous_exception_handler does a goto to a common block of assembly code that does the actual call. |
wli | In this case, we don't need to use the exception code except as a way to name the function. |
wli | Since they all need different symbols to be linked. |
wli | IDT_EXCEPTION_HANDLER_WITHOUT_CODE(ARITHMETIC_EXCEPTION_CODE, |
wli | arithmetic_exception); |
wli | This will define the symbol idt_entry_ARITHMETIC_EXCEPTION_CODE |
wli | Which is an ugly name, but that's okay, because it's distinct and not really used anywhere directly. |
wli | Now these exception handlers must handle segments once again: |
wli | Various other parts of the register state may not be saved without some intervention. |
wli | So to deal with this before C code is called: |
wli | raw_synchronous_exception_handler: |
wli | cld |
wli | pushal |
wli | pushw %ds |
wli | pushw %es |
wli | movw $KERNEL_DATA_SEGMENT, %ax |
wli | movw %ax, %ds |
wli | movw %ax, %es |
wli | call synchronous_exception_handler |
wli | Dealig with asynchronous exceptions or interrupts is largely similar. |
wli | Compared to the GDT, the IDT is simple, though. |
wli | The addresses of the idt_entry_ functions are encoded in the same way as the GDT, but basically only a couple of extra fields must be put in. |
wli | The same way as the GDT encodes segment base addresses that is. |
wli | #define IDT_ENTRY_ENCODE(SEGMENT, VECTOR) \ |
wli | ( \ |
wli | (((unsigned long long)IDT_INTERRUPT_GATE_TYPE) << 32) \ |
wli | | IDT_CODE_SEGMENT_ENCODE(SEGMENT) \ |
wli | | IDT_VECTOR_ENCODE(VECTOR) \ |
wli | ) |
wli | Once again, there is a record like the GDT's that describes the starting address and size of the IDT, and so the IDT record contains those and uses the same format. |
wli | And in a big code block, I do: |
wli | IDT_ENTRY_INITIALIZE(ARITHMETIC_EXCEPTION); |
wli | IDT_ENTRY_INITIALIZE(DEBUGGER_ENTRY_EXCEPTION); |
wli | IDT_ENTRY_INITIALIZE(NON_MASKABLE_INTERRUPT_EXCEPTION); |
wli | ... and so on |
wli | The asynchronous exceptions start at 32, though, and there aren't any special meanings for their numbers: |
wli | IDT_ASYNCHRONOUS_ENTRY_INITIALIZE(32); |
wli | IDT_ASYNCHRONOUS_ENTRY_INITIALIZE(33); |
wli | ... up to 47. |
wli | Then simply: |
wli | write_idt(&idt_record); |
wli | How am I doing on time? |
fernando | no problem with time |
wli | I don't want to run over too long. |
fernando | if people is ok ;) |
wli | I'm running out of time myself, unfortunately. |
wli | Sorry if this is a little rushed, but here goes. |
iaiox | no problem with time |
wli | Now, even though we are prepared to deal with exceptions if they are delivered to us, they won't be delivered to us unless the CPU itself has the option bit set that turns on the feature where it makes those function calls when the signals are received. |
wli | And also, the signals must be delivered to us from a device called an interrupt controller. |
wli | All of the signals for delivering exceptions from devices go through this interrupt controller. |
wli | There is a sort of userland equivalent to this: SIGIO |
wli | The part with the IDT is like sigaction(): if we get the signal, we call the handler function. |
wli | But now we have to tell the interrupt controller the fcntl() part. |
wli | There are two interrupt controllers, and they are tied together. |
wli | no problem |
wli | By using a special instruction to access their memory (actually called registers), you can issue commands to this device. |
erikm | wli: thanks for the lecture |
wli | It's called port I/O. |
wli | no problem |
wli | There are two I/O ports for each of the two twin interrupt controllers: |
surriel | I'll read the rest of the lecture in teh archive |
wli | I'm almost out of steam anyway. |
JALH | night all, thanks wli :) |
JALH | (clap clap clap clap clap) |
wli | Essentially a command and a data port. |
wli | The sequence is (1) tell the controller to initialize itself, inform it which interrupts are serviceable, whether it is the slave or if it is the master, where the slave is, and how it receives acknowledgments about the interrupt. |
wli | I myself wrote: |
wli | port_write8(IC0_COMMAND_PORT, IC_RESET_COMMAND); |
wli | port_write8(IC0_DATA_PORT, IC_VECTORS_SERVED); |
wli | ... |
wli | port_write8(IC1_DATA_PORT, IC_8086_EOI_MODE); |
wli | port_write8(IC1_DATA_PORT, IC_MASK_ALL_INTERRUPTS); |
wli | ... |
wli | And from there, the command to unmask the interrupts should be all you need to start receiving them. |
wli | One more important note, but not much detail: |
wli | The kernel is required to respond to timing information, and it receives an interrupt at regular intervals from a built-in device. |
wli | But that device must be initialized. |
wli | Otherwise it's all handled in the same way. |
wli | Unfortunately 3PM is my cutoff limit otherwise I'd go on. |
cdub | time for any questions? |
wli | I can post my example code in a short while. |
wli | Okay, I'll field a couple of questions before I take off. |
cdub | when you register a device (talking APIC here) is it possible to dictate whether it is XT-PIC or IO_APIC |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
wli | Yes and no. |
cdub | ;-) |
cdub | if you cat /proc/interrupts you'll see keyboard for example as XT-PIC |
wli | IO-APICs can emulate XT-PIC but there is hardware out there that is a real PIC, and can't be treated like an IO-APIC. |
wli | For instance, model 1 Athlons. |
JALH | clap clap clap clap clap clap! |
JALH | :) |
digiobi | thanks for the class |
fernando | plas plas plas plas plas plas plas plas plas plas plas |
fernando | plas plas plas plas plas plas plas plas plas plas plas |
fernando | plas plas plas plas plas plas plas plas plas plas plas |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
iaiox | clap clap clap ... thanks |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
wli | It was pretty basic, but I didn't want to get too far out there. |
iaiox | thanks a lot |
digiobi | is there notes or samples on the net? |
JALH | took me about 6 months to figure all that out :) |
wli | I'll get back to the conference coordinators about how to get at the sample code. |
cdub | thanks wli! i certainly learned something ;-) |
fernando | thank you to all for comming |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
JALH | you can test for an apic |
MJesus_ | clap clap clap clap clap clap clap clap clap clap |
digiobi | I learned something |
fernando | and thank you to the lecturer for this nice talk |
wli | The sample code boots & runs, so it could be worth looking at. |
wli | yes, but it's difficult. |
JALH | iirc there's a bit in cr0 or eflags that says there's one, no? |
fernando | let us remember that umeet finishes tomorrow |
JALH | and you can always massage the memory to see if there's one there |
wli | I don't understand the full details, a lot of it are workarounds for hardware bugs. |
digiobi | are there lectures in here often? |
sarnold | digiobi: well, for a while :) |
fernando | well, it depends on people interests |
fernando | we had some lectures in june about ipv6, security and so on |
sarnold | http://umeet.uninet.edu/ |
fernando | and now, we have had umeet |
fernando | what's next? |
fernando | who knows? |
fernando | ;) |
JALH | maybe we could have it in real life? |
JALH | :) |
fernando | if you feel that you can organize a talk |
Ryback_ | :) |
fernando | and you fell that this place would be ok for your talk |
sarnold | ah, I thought fernando meant, "what is next lecture in the umeet series?" :) |
fernando | come here and tell us |
cdub | this isn't real life? ;-) |
fernando | I understood he was talking about the future |
JALH | cdub, hmmm, tough question |
JALH | I irc therefore I am? |
JALH | :) |
cdub | hehe |
Ryback_ | :) |
digiobi | I'm trying to learn kernel stuff that's why I'm here :-) |
cdub | wli, THANKS! |
digiobi | wli thanks a lot |
fernando | tomorrow there will be a round table on ipv6 |
JALH | digiobi, see also openprojects.net/#kernelnewbies |
wli | anytime |
fernando | and, later |
fernando | a talk on the kernel janitors project |
digiobi | JALH: I was in there earlier, was pretty quiet. |
JALH | digiobi, wait till someone asks a question ;> |
JALH | just wait and soak up knowledge :) |
digiobi | JALH: hehe, well I'm interested in learning about Memory Management and task scheduling so hopefully I'll see something. |
JALH | yep |
JALH | for memory, ask a question when riel's around ;> |
digiobi | jahl: i'm starting to slowly go through bits of the linux kernel but getting started is that hard part |
sarnold | (can someone please check the time for that round table tomorrow? :) |
fernando | let me check |
MJesus_ | also come acme, and davej, and jgarzik |
MJesus_ | at 22 CET time |
fernando | there was a problem with one of our speakers |
JALH | ah yeah, there's some kernel janitors thing |
digiobi | well I enjoyed wli's lecture. I logged it so I can go over it more later |
fernando | and we didn't fix the round table time yet |
fernando | digi: we'll publish it in our web also |
sarnold | there, no time now :) |
fernando | we'll announce it as soon as possible |
digiobi | fernando: is that the umeet.uninet.edu page you listed earlier? |
fernando | yes |
digiobi | fernando: kewl, thx |
sarnold | fernando: where are the logs located? :) |
fernando | umeet.uninet.edu/umeet2001/english/des.eng.html |
VERTIGO | hola viZard |
digiobi | I might have to come back here more often. I help op #linuxhelp on undernet, but interested in learning the hardcore stuff |
viZard | hola |
fernando | the round table will be at 20:00 CET |
sarnold | fernando: gracias :) |
fernando | at 22:00 the kernel janitors project talk |
sarnold | there we are :) New time :) |
fernando | 20:00 |
fernando | at 22:00 is another different one |
sarnold | ooh :) nice compromise |
JALH | hehe |
fernando | later |
fernando | some music and fireworks ? |
fernando | hehe |
JALH | project |
digiobi | who was that who gave the lecture? |
sarnold | heh, I like 'proyect' more :) |
JALH | wli? |
sarnold | digiobi: wli? |
digiobi | yeah wli? |
J | Holas |
sarnold | 'night JALH :) |
IRC log ended Sat Dec 15 01:15 |