Autor Thema: x86 SMP  (Gelesen 12794 mal)

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« am: 13. January 2011, 00:21 »
Hi zusammen,

ich bin soweit, dass ich meinen Scheduler bedenkenlos schreiben kann.
Der Scheduler soll bei der Initialisierung alle anderen CPUs starten, damit das System möglichst schnell
alle CPUs verwendet.

Wie finde ich heraus, wie viele CPUs das System enthält?
Habe etwas mit der Floating Point Structure gefunden, werde daraus allerdings nicht schlau.

Was muss ich beim Booten der anderen CPUs beachten?
Sind die noch im RM?
Falls ja, müsste ich mir also erst Code schreiben, der sie dann in den PM holt, dann Speicher für den Stack besorgen und ab dann müssten sie laufen, oder (TSS fehlt auch noch)?

Gibt es sonst noch Probleme, die ich beachten muss?
Also mein Kernel ist von Grund auf für den SMP-Support designed.

Danke.

Gruß,
rizor
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #1 am: 13. January 2011, 00:29 »
Wie finde ich heraus, wie viele CPUs das System enthält? Habe etwas mit der Floating Point Structure gefunden, werde daraus allerdings nicht schlau.
Hast du dir schon den Wikiartikel dazu bzw. die dort ganz unten verlinkte Intel Multiprocessor Specification? Darin wird eigentlich sehr gut erklärt wie man an die Adresse der Strukturen kommt und wie sie aufgebaut sind. Am wichtigsten dürfte da wohl die physische Adresse der eigenen LAPIC sein (die brauchst du um den anderen CPUs einen Interprocessor Interrupt zu senden) und die LAPIC-ID der anderen Prozessoren.
Alternativ kann man das ganze auch über die ACPI-Tabellen machen. Ist kaum mehr Aufwand eigentlich und die modernere Variante.

Zitat
Was muss ich beim Booten der anderen CPUs beachten?
Darauf, dass du auf gemeinsame Strukturen nur synchronisiert (über Mutex, Semaphore, atomare Operation, etc...) zugreifst.

Zitat
Sind die noch im RM?
jo

Zitat
Falls ja, müsste ich mir also erst Code schreiben, der sie dann in den PM holt, dann Speicher für den Stack besorgen und ab dann müssten sie laufen, oder (TSS fehlt auch noch)?
IDT laden und Paging musst du natürlich auch aktivieren, ansonsten halt aufpassen, dass jede CPU einen eigenen Kernelstack hat (was mit dem eigenen TSS natürlich gemacht wird)

Zitat
Gibt es sonst noch Probleme, die ich beachten muss?
Wie oben erwähnt: Synchronisation; Der Code zum Booten der CPU muss natürlich unter 1MB sein
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 14. January 2011, 00:30 »
Danke, dann sollte es also an sich so funktionieren, wie ich es mir gedacht habe.
Allerdings habe ich noch zwei Fragen:
1. Wie kriege ich den Linker dazu, dass er mir 16-Bit Code linkt? Wo der liegt, ist bei mir in einer Sektion definiert.
2. Gibt es eine gute Seite für die ACPI-Tabellen? Habe mir zwar mal die Doku angeschaut, die ist aber recht unübersichtlich. Habe es jetzt soweit geschafft, dass ich die XSDT und RSDT Tabellen finde. Allerdings finde ich nicht alle Tabellen (die Strukturen, damit ich die Speichergrößen berechnen kann).

Habe mir auch mal den Linux-Code dazu angeschaut, der ist aber anders aufgebaut als die Beispiele von osdev.org. Ich behaupte mal, dass der Linux-Code stimmt (der läuft ja auch ;) ), aber ich habe halt kein schönes Tutorial gefunden und ich bin kein Fan von Copy&Paste, da ich das ja sonst nie verstehe.

Gruß,
rizor
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 14. January 2011, 10:55 »
Mal etwas zu ACPI.

Es möge auch gehen über die ACPI Tabellen, andere CPUs zu finden, aber sobald man mit Interrupts/IRQs arbeiten möchte, wird man wohl wieder die MP Tabellen nehmen.
Denn um die Routing Informationen für die IRQs zu bekommen, braucht man ne vollständige ACPI Umgebung und ich gehe mal davon aus das die hier noch keiner hat und auch keiner vorhat sowas selbst zu schreiben.

Also würde ich mich erstmal auf die MP Tabellen konzentrieren und wenn damit dann mal alles läuft (also auch IRQ Routing) dann kann man sich immer noch mit ACPI rumschlagen!

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #4 am: 14. January 2011, 10:58 »
1. Wie kriege ich den Linker dazu, dass er mir 16-Bit Code linkt? Wo der liegt, ist bei mir in einer Sektion definiert.
Ich glaub FreakyPenguin hat da mal irgendwas gemacht

Zitat
2. Gibt es eine gute Seite für die ACPI-Tabellen? Habe mir zwar mal die Doku angeschaut, die ist aber recht unübersichtlich. Habe es jetzt soweit geschafft, dass ich die XSDT und RSDT Tabellen finde. Allerdings finde ich nicht alle Tabellen (die Strukturen, damit ich die Speichergrößen berechnen kann).
Es reicht den Aufbau der Tabellen zu kennen die du brauchst. Zuerst musst du die RSDT finden, den Aufbau sieht man in Tabelle 5-7 (alles hier bezieht sich auf ACPI Spec 3.0a). Physisch hinter der Header der RSDT kommen 32Bit-Pointer auf weitere Tabellen. Jede dieser Tabellen hat am Anfang die Description header (Tabelle 5-4) und im speziellen eine Signature darin. Diese dient mit Tabelle 5-5 dazu die Tabellen zu finden die du brauchst, was wahrscheinlich "APIC" ist. Dann musst du halt in dem Kapitel dieser Tabelle nachschauen wie sie aufgebaut ist. Beispielcode sollte es irgendwo in pedigree (hier und hier) dazu geben, falls du welchen brauchst.
« Letzte Änderung: 14. January 2011, 11:05 von bluecode »
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 18. January 2011, 13:36 »
Danke für die Beiträge, ich bin jetzt auf die Intel MP umgestiegen (lief sehr viel unkomplizierter ;)).
Nun bin ich dabei mir einen APIC-Treiber zu schreiben.
Dabei habe ich eine Frage:
Den PIC konnte man ja rerouten, damit er seine IRQ an andere Leitungen schickt, damit das dann zur IDT passt. Kann die APIC das auch? Habe was von Dest-ID gelesen, war mir aber nicht sicher, ob es das ist.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #6 am: 18. January 2011, 14:12 »
Zuerstmal solltest du zwischen I/O APIC und LAPIC unterscheiden. Die LAPIC gibts einmal pro Prozessor und die I/O APIC einmal (oder mehrmals) im ganzen System. Die I/O APIC dient dazu die IRQs an die Prozessoren (im Speziellen an die LAPIC der Prozessoren) zu verteilen und die LAPIC dient dazu dem Prozessor dann den entsprechenden Interrupt zu signalisieren. Die Übersetzung von IRQ- nach Interruptnummer erfolgt dabei bereits in der I/O APIC über deren Redirection Table. Darüber hinaus steht in der Tabelle die ID der LAPIC an den der Interrupt gehen soll. Die anderen Einträge der Redirection Table kann man mehr oder minder den MP- bzw. ACPI-Tabellen entnehmen.
Das Rerouting geht also über die I/O APIC. Man muss allerdings nicht die I/O APIC verwenden sondern kann auch die gute alte PIC verwenden. Das Rerouting funktioniert dann "ganz normal" (und alle IRQs gehen an den Bootprozessor).
Und dann noch was ganz anderes: Die LAPIC bietet auch noch eigene, neue Interrupts an (einen Fehlerinterrupt, einen tollen Timer den man zB zum Schedulen verwenden kann). Die Interruptnummer dieser Interrupts kann man in der LAPIC ändern.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

freecrac

  • Beiträge: 86
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 19. January 2011, 12:38 »
Möglicherweise kann dieses Listing etwas weiter helfen:

http://www2.cs.usfca.edu/~cruse/cs630f08/mphello.s

//-----------------------------------------------------------------
// mphello.s
//
// This program employs Intel's MP Initialization Protocol
// to awaken any auxilliary processors that may be present
// and allows each processor to display its APIC Local-ID.
//
// to assemble: $ as mphello.s -o mphello.o
// and to link: $ ld mphello.o -T ldscript -o mphello.b
// and install: $ dd if=mphello.b of=/dev/sda4 seek=1
//
// NOTE: This code begins executing with CS:IP = 1000:0002.
//
// programmer: ALLAN CRUSE
// written on: 31 OCT 2008
//-----------------------------------------------------------------


# manifest constants
.equ APIC_BASE, 0xFEE00000 # base-address for APIC
.equ realCS, 0x1000 # arena segment-address


.section .text
#------------------------------------------------------------------
.word 0xABCD # our loader expects this
#------------------------------------------------------------------
main: .code16 # for real-mode execution
mov %sp, %cs:ipltos+0 # preserve loader's SP
mov %ss, %cs:ipltos+2 # preserve loader's SS

mov %cs, %ax # address program arena
mov %ax, %ss #   using SS register
lea tos, %sp # establish local stack

call allow_4GB_addressing
call display_APIC_LocalID
call broadcast_AP_startup
call delay_until_APs_halt

lss %cs:ipltos, %sp # recover loader's SS:SP
lret # return control to loader
#------------------------------------------------------------------
ipltos: .word 0, 0 # holds loader's SS and SS
#------------------------------------------------------------------
# We must briefly enter protected-mode to arrange for APIC access
#
theGDT: .quad 0x0000000000000000 # required null-descriptor

.equ sel_FS, (.-theGDT)+0 # 'flat' segment-selector
.quad 0x008F92000000FFFF # 4GB (readable/writable)

.equ limGDT, (.-theGDT)-1 # our GDT's segment-limit 
#------------------------------------------------------------------
regGDT: .word limGDT, theGDT, 0x0001 # register-image for GDTR
#------------------------------------------------------------------
#------------------------------------------------------------------
allow_4GB_addressing:
#
# Here we setup register FS, so it can access the APIC registers.
#
pushf # preserve current flags
cli # and disable interrupts

mov %cr0, %eax # get CPU's register CR0
bts $0, %eax # turn on PE-bit's image
mov %eax, %cr0 # enter 'protected-mode'

lgdt %cs:regGDT # setup GDT for this CPU

mov $sel_FS, %ax # flat-segment's selector
mov %ax, %fs # raises FS segment-limit

mov %cr0, %eax # get CPU's register CR0
btr $0, %eax # reset image for PE-bit
mov %eax, %cr0 # go back to 'real-mode'

xor %ax, %ax # load base-address zero
mov %ax, %fs # for our 'flat' segment

popf # restore previous flags
ret
#------------------------------------------------------------------
msg: .ascii "Hello from processor " # message from processor
pid: .ascii "    " # buffer for CPU LocalID
.ascii "CR0=" # legend for CR0 display
msw: .ascii "xxxxxxxx \n\r" # buffer for CR0 content
len: .short .- msg # length of message-text
att: .byte 0x0B # message attribute-byte

mutex: .word 1 # mutual-exclusion flag
n_APs: .word 0 # count of awakened APs
n_fin: .word 0 # count of finished APs
newSS: .word 0x2000 # stack segment-address

hex: .ascii "0123456789ABCDEF" # table of hex numerals
#------------------------------------------------------------------
eax2hex:  # converts value in EAX to hexadecimal string at DS:DI

pushal
mov $8, %cx # number of nybbles
nxnyb:
rol $4, %eax # next nybble into AL
mov %al, %bl # copy nybble into BL
and $0x0F, %bx # and convert to word
mov hex(%bx), %dl # lookup ascii numeral
mov %dl, (%di) # put numeral in buffer
inc %di # advance buffer address
loop nxnyb # again for next nybble
popal
ret
#------------------------------------------------------------------
#------------------------------------------------------------------
display_APIC_LocalID:
#
# This procedure will be executed by each of the processors, but
# because its message-buffer requires mutually exclusive access,
# and because ROM-BIOS int-0x10 routines are not 'reentrant', we
# must insure that only one CPU at a time can execute this code,
# so we employ a 'spinlock' (and utilize the x86 'lock' prefix).
#
mov %cs, %ax # address program arena
mov %ax, %ds #   with DS register
mov %ax, %es #   also ES register

# acquire the spinlock -- so only one CPU at a time can
# modify the message-text and call BIOS video functions

spin: bt $0, mutex # mutex is available?
jnc spin # no, wait till it is

lock # exclusive bus-access
btr $0, mutex # try to grab the mutex
jnc spin # spin until successful

# put this CPU's Local-APIC ID-register in message-text

mov $APIC_BASE, %ebx #
mov %fs:0x20(%ebx), %eax # ID-register's value
rol $8, %eax # rotate ID into AL
and $0x0F, %al # isolate lowest nybble
add $'0', %al # convert to a numeral
mov %al, pid # and put into message

# format contents of this CPU's register CR0 for display

mov %cr0, %eax # load value from CR0
lea msw, %di # point DS:DI to buffer
call eax2hex # convert value to hex

# invoke ROM-BIOS functions to write  message onto screen

mov $0x0F, %ah # get_display_page
int $0x10 # invoke BIOS service
mov $0x03, %ah # get_cursor_location
int $0x10 # invoke BIOS service
lea msg, %bp # point ES:BP to string
mov len, %cx # string's length in CX
mov att, %bl # color-attribute in BL
mov $0x1301, %ax # write_string
int $0x10 # invoke BIOS service

# we have now finished with this 'non-reentrant' code

bts $0, mutex # release the spinlock

ret
#------------------------------------------------------------------
#------------------------------------------------------------------
delay_EAX_microseconds:
#
# This helper-function will implement the timed delays which are
# specified in Intel's 'Multiprocessor Initialization Protocol',
# where the delay-duration (in microseconds) is in register EAX.
#
pushal

mov %eax, %ecx # copy microseconds count

# enable the 8254 Channel-2 counter
in $0x61, %al # get PORT_B settings
and $0x0D, %al # turn PC speaker off
or $0x01, %al # turn on Gate2 input
out %al, $0x61 # output new settings

# program channel-2 for one-shot countdown
mov $0xB0, %al # chan2,LSB/MSB,one-shot
out %al, $0x43 # output command to PIT

# compute value for channel-2 latch-register
mov $1193182, %eax # input-pulses-per-second
mul %ecx # * number of microseconds
mov $1000000, %ecx # microseconds-per-second
div %ecx # division by doubleword

# write latch-resister value to channel-2
out %al, $0x42
mov %ah, %al
out %al, $0x42

# wait for channel-2 countdown to conclude
nxpoll: in $0x61, %al
test $0x20, %al
jz nxpoll

# disable the 8254 Channel-2 counter
in $0x61, %al # get PORT_B settings
and $0x0C, %al # turn off channel-2
out %al, $0x61 # output new settings

popal
ret
#------------------------------------------------------------------
delay_until_APs_halt:
#
# Here the BootStrap Processor waits for all the APs to finish.
#
sti # allow timer interrupts
check: hlt # halt until interrupted
mov n_APs, %ax # number of awakened APs
sub n_fin, %ax # equals number finished?
jnz check # no, check again later 
ret
#------------------------------------------------------------------
#------------------------------------------------------------------
broadcast_AP_startup:
#
# This procedure is executed only by the BootStrap Processor, to
# awaken the Auxilliary Processors so that they each can display
# their Local-APIC ID-number (and their CR0 register's value, so
# we can verify that the cache-related bits are setup properly).
# We use code here which follows the MP Initialization Protocol.
#
# point FS:EBX to the Local-APIC's memory-mapped page
xor %ax, %ax # address segment zero
mov %ax, %fs #   with FS register
mov $APIC_BASE, %ebx # APIC address in EBX

# compute the page-number (where each AP should start)
mov $realCS, %edx # arena segment-address
shl $4, %edx # multiplied by sixteen
add $tos, %edx #  plus entry's offset
shr $12, %edx # divided by page-size
and $0xFF, %edx # must be in bottom 1MB

# issue an 'INIT' Inter-Processor Interrupt command
mov $0x000C4500, %eax # broadcast INIT-IPI
mov %eax, %fs:0x300(%ebx) # to all-except-self

# do ten-millisecond delay, enough time for APs to awaken
mov $10000, %eax # ten-thousand microseconds
call delay_EAX_microseconds # execute programmed delay

# wait for indication of the command's completion
spin1: bt $12, %fs:0x300(%ebx) # command-in-progress?
jc spin1 # yes, spin until done

#--------------------------------------------------------
# now we complete the Intel 'MP Initialization Protocol'
#--------------------------------------------------------
mov $2, %ecx # protocol's repetitions
nxIPI:
# issue a 'Startup' Inter-Processor Interrupt command
mov $0x000C4600, %eax # issue 'Startup-IPI'
mov %dl, %al # page is the vector
mov %eax, %fs:0x300(%ebx) # to all-except-self

# delay for 200 microseconds
mov $200, %eax # number of microseconds
call delay_EAX_microseconds # for a programmed delay

# wait for indication of the command's completion
spin2: bt $12, %fs:0x300(%ebx) # command-in-progress?
jc spin2 # yes, spin until done

# repeat this 'Statup-IPI' step twice (per the protocol)
loop nxIPI # again for MP protocol

ret
#------------------------------------------------------------------
#------------------------------------------------------------------
initAP:
#
# This procedure will be executed by each Application Processor as
# it is awakened by the BootStrap Processor sending Startup-IPI's.
# In order that each processor can call subroutines, it requires a
# private stack-area, which we setup sequentially using the 'xadd'
# instruction (to guarantee that stack-areas are non-overlapping).
# But until its stack is ready, this CPU cannot handle interrupts.
#
cli # disable interrupts

mov %cs, %ax # address program arena
mov %ax, %ds #   using DS register
mov %ax, %es #    and ES register

# increment the count of processors that have awakened
lock # insure 'atomic' update
incw n_APs # increment the AP count

# setup an exclusive stack-region for this processor

mov $0x1000, %ax # paragraphs in segment
xadd %ax, newSS # 'atomic' xchg-and-add
mov %ax, %ss # segment-address to SS
xor %esp, %esp # top-of-stack into ESP

# call subroutines to display this processor's Local-ID

call allow_4GB_addressing # adjust FS seg-limit
call display_APIC_LocalID # display this CPU's ID

# increment the count of processors that have finished
lock # insure 'atomic' update
incw n_fin # when modifying counter

# now put this processor to sleep
sleep: cli # do not awaken this CPU
hlt # 'fetch-execute' ceases
jmp sleep # just-in-case of an NMI
#------------------------------------------------------------------
.org 4096 # insures page-alignment
tos: ljmp $realCS, $initAP # initialize awakened AP
#------------------------------------------------------------------
.end # nothing else to assemble

Dirk

DerHartmut

  • Beiträge: 236
    • Profil anzeigen
    • Mein Blog
Gespeichert
« Antwort #8 am: 19. January 2011, 13:34 »
pastebin.com ...
$_="krJhruaesrltre c a cnp,ohet";$_.=$1,print$2while s/(..)(.)//;
Nutze die Macht, nutze Perl ;-)

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 19. January 2011, 13:41 »
danke, aber der code wird mir nur sehr bedingt helfen.
wie ich eine cpu in dem PM hole, weiß ich und was dann geschieht hängt ja vom kernel ab
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 29. January 2011, 00:16 »
Ich habe gerade ein Problem damit, dass ich meinen 16-bit Code zwar in meine ELF-Datei gelinkt bekomme, aber dann bootet mein System nicht mehr.

Hier mal der Code aus dem Linkerskript:
SECTIONS
{
. = 0x100000;

__kernel_entry = .;
__init_entry = .;
__smp_init_entry = LOADADDR(.smp_init);
                                 .smp_init 0x7000 : AT(__init_entry) {
                *(.smp_init)
}
__smp_init_end = LOADADDR(.smp_init) + SIZEOF(.smp_init);
__init32_entry = LOADADDR(.smp_init) + SIZEOF(.smp_init);
.init32 (LOADADDR(.smp_init) + SIZEOF(.smp_init)) : {
*(.multiboot)
*(.init32_text)
*(.init32_data)
}
__init32_end = .;
__init_end = .;

. = ALIGN(0x1000);

Hier jetzt noch mein Trampolin-Code:
#if defined(CONFIG_ARCH_I386) && defined(CONFIG_SMP)

.extern gdt;
.extern idt;
.extern smp_ap_init

.section .smp_init,"aw",@progbits
.code16

start_up:
    cli
    lgdtl gdtr

xor %ax , %ax
inc %ax
lmsw %ax
    ljmp $0x0000 , $code_32

.code32
code_32:
    mov $0x10 , %eax
    mov %eax , %ds
mov %eax , %es
mov %eax , %fs
mov %eax , %gs
mov %eax , %ss
lidtl idt
jmp smp_ap_init

gdtr:
    .word 24
    .long gdt

gdt:
    .word 0x0000
    .word 0x0000
    .word 0x0000
    .word 0x0000
    .word 0xFFFF
    .word 0x0000
    .word 0x9800
    .word 0x00CF
    .word 0xFFFF
    .word 0x0000
    .word 0x9200
    .word 0x00CF

#endif

Was mache ich da falsch?

Gruß,
rizor
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 29. January 2011, 11:47 »
Sinnvoll wäre noch wenn du rausbekommst wo er genau aussteigt und am besten noch warum ;) Bochs hilft bei sowas eigentlich immer und unter Qemu kannst du nachschauen ob der Speicher wirklich das enthält was du erwartest.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 29. January 2011, 14:04 »
Unter Qemu steigt er noch vor meinem Code aus. Es wird noch nicht einmal mein Assembler-Init Code aufgerufen.
Die CPU wirft eine GPF und steigt später mit einem Triple Fault aus.
Ich kann mir nicht wirklich erklären warum.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 29. January 2011, 15:13 »
Du musst erstmal ungefähr rausfinden bis wohin dein Code kommt. Also am besten probieren ob es ohne diesen Trampolin Code funktioniert und ob es mit Trampoline Code funktioniert, aber ohne das er benutzt wird.

Bochs sagt dir sogar wo der GPF passiert (oder fängt den dein Exception Code ab?) und da kann man dann anfangen mit suchen.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 29. January 2011, 15:20 »
Ohne den Trampolin-Code funktioniert alles einwandfrei. Sobald er in den Kernel gelinkt wird, läuft alles schief. Mein Code muss innerhalb des Assembler-Codes des BSP fliegen. Der Kernel bootet nicht, sondern wird vorher schon durch den Triple Fault ausgelöst.
Ich installiere mir gerade mal Bochs, damit ich die Info kriege.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 29. January 2011, 16:35 »
Habe den Code mal versucht unter Bochs zu starten, aber da bootet GRUB den Kernel nicht.
Er meldet, dass er nicht unterhalb eines MB mappen kann.
Wie kriege ich das Problem denn behoben?
Wenn ich dem Linker sage, dass es woanders liegen soll, kann er natürlich nicht den 16-bit code richtig alignen.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 29. January 2011, 16:41 »
Ich habe das mit dem Trampolin-Code ganz anders gelöst, aber ich mache das auch in meinem Loader.

Das mache ich unter nasm:
smpTrampolin:
%incbin "smp-stub.bin"
smpTrampolinEnd:

Im Endeffekt schreibe ich in einer extra Datei den Trampoline-Code (welcher eh an eine feste Adresse kopiert werden muss), assembliere das ganze und füge dann den schon assemblierten Code in eine andere Assembler Datei ein, so weiß der Linker nicht das ich eigentlich 16bit/32bit Misch-Masch-Code dabei habe. Ich kann dann unter C einfach smpTrampolin und smpTrampolinEnd benutzen um den Code an die gewünschte Stelle zu kopieren und die APs dann ausführen zu lassen.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 29. January 2011, 17:01 »
So könnte ich es auch machen, aber geht es nicht auch irgendwie anders?
Freaky hat es doch geschafft oder benutzt er einen eigenen Bootloader, der auch unterhalb von einem MB mappen kann?
Gibt es eine Möglichkeit unter GAS, dass er den Code gegen eine bestimmte Adresse linkt, ihn aber woanders hinlegt, damit der Code über der einen MB Grenze liegt?
Ich möchte an sich nur ungerne den Umweg über NASM machen, da ich an sich lieber nur die binutils verwenden möchte.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #18 am: 29. January 2011, 17:05 »
Was FlashBurn macht hat ja nichts mit NASM an sich zu tun. Du kannst genauso deinen Trampolinecode mit gas zu einer binary (!) assemblieren und dann mit incbin einbinden und während der Laufzeit an die richtige Stelle kopieren, das habe ich auch so gemacht.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 29. January 2011, 18:25 »
Wie habt ihr das denn gelöst mit unaufgelösten Symbolen?
Habe in meinem PM-Code Symbole auf Code in meinem Kernel, damit die CPU den Rest von sich initialisieren kann und dann mit dem Scheduling gelöst.
Habe Versucht mir gerade die Binary zu bauen, aber da kann der Linker natürlich nicht alles auflösen.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

 

Einloggen